Privés méthodes helper être statique si elles peuvent être statiques
disons que j'ai une classe conçue pour être instancié. J'ai plusieurs méthodes "d'aide" privées au sein de la classe qui n'exigent pas l'accès à l'un des membres de la classe, et fonctionnent uniquement sur leurs arguments, retournant un résultat.
public class Example {
private Something member;
public double compute() {
double total = 0;
total += computeOne(member);
total += computeMore(member);
return total;
}
private double computeOne(Something arg) { ... }
private double computeMore(Something arg) {... }
}
y a - t-il une raison particulière de préciser computeOne
et computeMore
comme méthodes statiques-ou une raison particulière de ne pas le faire?
Il est certainement plus facile de les laisser comme non-statique, même bien qu'ils puissent certainement être statiques sans causer de problèmes.
21 réponses
je préfère que ces méthodes d'aide soient private static
; ce qui indiquera clairement au lecteur qu'elles ne modifieront pas l'état de l'objet. Mon IDE montrera aussi des appels vers des méthodes statiques en italique, donc je saurai que la méthode est statique sans regarder la signature.
il pourrait en résulter un bytecode légèrement plus petit, puisque les méthodes statiques ne seront pas obtenir l'accès à this
. Je ne pense pas que cela fasse une différence dans la vitesse (et si c'était le cas, ce serait probablement trop petit pour faire une différence dans l'ensemble).
je les rendrais statiques, puisque je le fais généralement si possible. Mais c'est juste moi.
EDIT: cette réponse n'arrête pas d'être dévalorisée, peut-être à cause de l'affirmation non fondée sur la taille du bytecode. Donc, je vais d'ailleurs lancer un test.
class TestBytecodeSize {
private void doSomething(int arg) { }
private static void doSomethingStatic(int arg) { }
public static void main(String[] args) {
// do it twice both ways
doSomethingStatic(0);
doSomethingStatic(0);
TestBytecodeSize t = new TestBytecodeSize();
t.doSomething(0);
t.doSomething(0);
}
}
Bytecode (extrait avec javap -c -private TestBytecodeSize
):
Compiled from "TestBytecodeSize.java"
class TestBytecodeSize extends java.lang.Object{
TestBytecodeSize();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: return
private void doSomething(int);
Code:
0: return
private static void doSomethingStatic(int);
Code:
0: return
public static void main(java.lang.String[]);
Code:
0: iconst_0
1: invokestatic #2; //Method doSomethingStatic:(I)V
4: iconst_0
5: invokestatic #2; //Method doSomethingStatic:(I)V
8: new #3; //class TestBytecodeSize
11: dup
12: invokespecial #4; //Method "<init>":()V
15: astore_1
16: aload_1
17: iconst_0
18: invokespecial #5; //Method doSomething:(I)V
21: aload_1
22: iconst_0
23: invokespecial #5; //Method doSomething:(I)V
26: return
}
invoquer la méthode statique prend deux bytecodes (byteops?): iconst_0
(pour l'argument) et invokestatic
.
Invoquant la non-statique méthode prend trois: aload_1
(pour le TestBytecodeSize
objet, je suppose), iconst_0
(pour les argument), et invokespecial
. (Notez que si ces méthodes n'avaient pas été privées, il aurait été invokevirtual
au lieu de invokespecial
; voir JLS §7.7 Invoking Methods .)
maintenant, comme je l'ai dit, Je ne m'attends pas à ce qu'il y ait une grande différence dans la performance entre ces deux, si ce n'est le fait que invokestatic
nécessite un bytecode de moins. invokestatic
et invokespecial
devraient tous deux être légèrement plus rapides que invokevirtual
, car ils utilisent tous les deux reliure statique au lieu de dynamique, mais je n'ai aucune idée si l'un est plus rapide que l'autre. Je ne trouve pas de bonnes références. Le plus proche que je peux trouver est cet article de JavaWorld 1997 , qui reprend essentiellement ce que je viens de dire:
les instructions les plus rapides seront probablement
invokespecial
etinvokestatic
, parce que les méthodes invoquées par ces instructions sont statiquement liées. Lorsque la JVM résout la référence symbolique pour ces instructions et le remplace par une référence directe, cette référence directe inclura probablement un pointeur vers les bytecodes réels.
Mais beaucoup de choses ont changé depuis 1997.
en conclusion... Je crois que je m'en tiens toujours à ce que j'ai dit. La vitesse ne devrait pas être la raison de choisir l'un par rapport à l'autre, car ce serait une micro-optimisation au mieux.
ma préférence personnelle serait de les déclarer statiques, car c'est un signal clair qu'ils sont apatrides.
la réponse est... il dépend.
si member est une variable d'instance spécifique à l'objet que vous traitez, alors pourquoi la passer comme paramètre?
par exemple:
public class Example {
private Something member;
public double compute() {
double total = 0;
total += computeOne();
total += computeMore();
return total;
}
private double computeOne() { /* Process member here */ }
private double computeMore() { /* Process member here */ }
}
une des raisons pour lesquelles vous pourriez vouloir déclarer les méthodes static helper est si vous devez les appeler dans la classe constructeur" avant " this
ou super
. Par exemple:
public class MyClass extends SomeOtherClass {
public MyClass(String arg) {
super(recoverInt(arg));
}
private static int recoverInt(String arg) {
return Integer.parseInt(arg.substring(arg.length() - 1));
}
}
C'est un peu un exemple artificiel mais clairement recoverInt
ne peut pas être une méthode d'instance dans cette affaire.
Je ne peux pas vraiment penser à des avantages clairs pour la méthode statique privée. Cela dit, il n'y a pas non plus d'avantages spécifiques à les rendre non statiques. C'est principalement une question de présentation : vous pourriez vouloir les rendre statiques pour souligner clairement le fait qu'ils ne modifient pas un objet.
pour une méthode avec des privilèges d'accès différents, je pense qu'il y a deux arguments principaux:
- les méthodes statiques peuvent être appelées sans créer une instance d'un objet, qui peut être utile
- les méthodes statiques ne peuvent pas être héritées, ce qui peut être un problème si vous avez besoin de polymorphisme (mais n'est pas pertinent pour les méthodes privées).
en outre, la différence est assez faible, et je doute fortement que le supplément de ce pointeur passé à la méthode d'instance fait une différence significative.
la bonne réponse est:
toute méthode qui ne prend aucune information d'un champ, et ne met aucune information dans un champ, ne doit pas être une méthode d'instance. Toute méthode qui n'utilise pas ou modifier des champs dans sa classe ou un objet pourrait aussi bien être une méthode statique.
ou une raison particulière de ne pas [les déclarer comme statiques]?
Oui.
en les gardant comme méthodes d'instance, vous vous autorisez à fournir une implémentation différente plus tard.
cela peut sembler stupide (et en fait ce serait si ces méthodes sont utilisées seulement par vous dans un programme de 50 lignes) mais dans les applications plus grandes, ou dans les bibliothèques utilisées par quelqu'un d'autre, vous pouvez décidez de choisir une meilleure implémentation, mais ne voulez pas briser le code existant.
donc vous créez une sous-classe et vous retournez que dans les nouvelles versions, et puisque les méthodes ont été déclarées comme des méthodes d'instance, vous laissez le polymorphisme faire son travail.
en outre, vous pourriez bénéficier de rendre le constructeur privé et de fournir une méthode d'usine statique pour la même raison.
Donc, ma recommandation est de les garder comme exemple méthodes, et d'éviter statique si possible.
Profitez du dynamisme de la langue.
voir ici pour une vidéo un peu liée: comment concevoir une bonne API et pourquoi il importe
bien qu'il ne soit pas directement lié à la discussion sur la méthode" static vs instance", il touche à certains points intéressants dans la conception de L'API.
si la méthode est fondamentalement juste un sous-programme qui ne sera jamais l'utilisation prévisible de l'information d'état, déclarez-le statique.
cela permet de l'utiliser dans d'autres méthodes statiques ou dans l'initialisation de classe, i.e.:
public class Example {
//...
//Only possible if computeOne is static
public final static double COMPUTED_ONE = computeOne(new Something("1"));
//...
}
L'un des problèmes que posent les méthodes statiques est qu'elles peuvent rendre l'objet plus difficile à utiliser dans les unit tests . Mockito ne peut pas créer des moqueries pour les méthodes statiques et vous ne pouvez pas créer une implémentation de la méthode par sous-classe.
Ma préférence dans des cas comme celui-ci est de faire computeOne
et computeMore
méthodes statiques. La raison: encapsulation. Le moins de code qui a accès à la mise en œuvre de votre classe, le mieux.
dans l'exemple que vous donnez, vous déclarez que computeOne
et computeMore
ne devraient pas avoir besoin d'accéder aux internes de la classe, alors pourquoi donner l'occasion aux mainteneurs de la classe de se mêler aux internes.
je voudrais clarifier peu de choses que d'autres affiches ont dit comme donnant des informations fausses.
tout d'abord parce que les méthodes sont privées même si vous les déclarez statiques, vous ne pourrez pas y accéder en dehors de cette classe. Deuxièmement, ils sont privés de sorte que vous ne pouvez même pas outrepasser dans la sous-classe afin statique ou non-statique ne fait aucune différence. Troisièmement, une méthode privée non statique peut être appelé d'un constructeur de la classe aussi, il n'est pas nécessaire d'être statique.
vient maintenant à votre question si une méthode d'aide privée devrait être définie comme statique ou non-statique. Je vais suivre la réponse de Steve comme la notation d'une méthode privée statique montre que cette méthode est apatride que je suis aussi cette règle quand je code.
la question Statique/non-statique se résume à"Ai-je vraiment besoin d'utiliser un objet de cette classe?"
alors, est-ce que vous passez l'objet entre différentes méthodes? L'objet contient des informations utiles en dehors du contexte des méthodes statiques? Y a-t-il une raison de ne pas définir les méthodes dans les deux sens si vous les utilisez dans les deux sens?
Si vous êtes dans ce dilemme, il me semble que vous avez toutes les données nécessaires pour la méthode flottant autour dans votre code à l'extérieur de l'objet. Est-ce que vous souhaitez? Serait-il plus facile de toujours collecter ces données dans un objet à chaque fois? Vous pourriez juste être ambivalent à propos de s'engager à un modèle unique. Si vous pouvez faire tout cela en utilisant une seule voie, puis choisir soit statique ou non-statique et aller avec elle.
plus précisément à l'exemple que vous avez donné, il semble que le but de définir ces méthodes est plus pour la clarté du code quand vous le lisez que pour la fonctionnalité (ils sont définis comme privé). Dans ce cas, aller avec static ne fait vraiment rien pour vous, puisque le but de static est d'exposer la fonctionnalité de classe.
D'après mon expérience, je dirais que de telles méthodes privées ont tendance à être tout à fait universelles et réutilisables.
je pense que la première chose à faire est de se demander si la méthode peut être utile en dehors du contexte de classe actuel. Si c'est le cas, je ferais exactement ce que tout le monde suggère et extraire cette méthode comme statique à une certaine classe utils où quelqu'un espère vérifie avant de mettre en œuvre la nouvelle méthode faisant exactement la même chose.
tel que général utiliser des méthodes privées sont la source d'une grande partie de la duplication de code dans le projet parce que chaque développeur les réinvente indépendamment juste à l'endroit où elle a besoin de l'utiliser. Donc, la centralisation de ces méthodes est un chemin à parcourir.
une raison est que, toutes choses étant égales par ailleurs, les appels de méthode statiques devraient être plus rapides. Les méthodes statiques ne peuvent pas être virtuelles, et ne prennent pas implicitement cette référence.
hors sujet: je garderais les méthodes helper dans une classe utilitaire/helper autonome avec seulement des méthodes statiques.
le problème avec avoir des méthodes d'aide au point d'utilisation (lire 'même classe' ) est que quelqu'un en bas de la ligne peut juste choisir d'afficher leurs propres méthodes d'aide non liées dans le même endroit
class Whatever {
public static varType myVar = initializeClassVariable();
private static varType initializeClassVariable() {
//initialization code goes here
}
}
l'avantage des méthodes statiques privées est qu'elles peuvent être réutilisées plus tard si vous avez besoin de réinitialiser la variable de classe.
-
sans le modificateur statique vous ne pouvez pas comprendre que la méthode est apatride sans analyse supplémentaire qui peut être facilement fait lorsque vous (re)écrire la méthode.
-
alors le modificateur "statique" peut vous donner des idées sur le remaniement en plus d'autres choses que d'autres pourraient trouver inutilisables. Par exemple: déplacer la méthode à une certaine classe D'utilité ou la convertir à une méthode de membre..
je les déclarerais statiques pour les marquer comme apatrides.
Java n'a pas de meilleur mécanisme pour les opérations mineures qui ne sont pas exportées, donc je pense que la statique privée est acceptable.
comme beaucoup de gens ont dit, Faites-Le est comme un statique ! Voici la règle du pouce que je suis: si vous pensez que la méthode est juste un fonction mathématique I. e il est apatride, n'implique Aucune variable d'instance(=> pas de vars de couleur bleue [dans eclipse] dans la méthode), et le résultat de la méthode sera le même pour le nombre 'n' d'appels (avec les mêmes paramètres, bien sûr), puis marquez cette méthode comme statique.
et si vous pensez que cette méthode sera utile à une autre classe alors déplacez-la à une classe Util autrement, mettez la méthode en tant que privé dans la même classe. (minimisation de l'accessibilité)