213 votes

Les méthodes d'aide privées devraient-elles être statiques si elles peuvent être statiques

Disons que j'ai une classe conçue pour être instancié. J'ai plusieurs privée "helper" méthodes à l'intérieur de la classe qui ne nécessitent pas l'accès à tous les membres de la classe, et agissent uniquement sur leurs arguments, de retourner 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) {... } 
}

Est-il une raison particulière pour spécifier computeOne et computeMore que des méthodes statiques ou une raison particulière de ne pas?

Il est certainement plus facile de les laisser comme non-statique, même si elles peuvent certainement être statique sans causer de problèmes.

178voto

Esko Luontola Points 53877

Je préfère que ces méthodes auxiliaires soient private static ; ce qui fera comprendre au lecteur qu'ils ne modifieront pas l'état de l'objet. Mon IDE affichera également les appels aux méthodes statiques en italique, donc je saurai que la méthode est statique sans regarder la signature.

112voto

Michael Myers Points 82361

Il pourrait en résulter, en légèrement plus petit bytecode, depuis les méthodes statiques de ne pas obtenir de l'accès à l' this. Je ne pense pas que cela fait une différence dans la vitesse (et si elle le faisait, il serait probablement trop petit pour faire une différence dans l'ensemble).

Je voudrais rendre statique, depuis que j'ai généralement le faire si possible. Mais c'est juste moi.


EDIT: Cette réponse ne cesse de s'downvoted, probablement en raison de l'affirmation sans fondement au sujet de bytecode à la taille. 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 (récupéré 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

}

L'invocation de la méthode statique prend deux bytecode (byteops?): iconst_0 (pour l'argument) et invokestatic.
Invoquant la non-statique méthode prend trois: aload_1 (pour l' TestBytecodeSize objet, je suppose), iconst_0 (pour l'argument), et invokespecial. (Notez que si ce n'avait pas été privé de méthodes, il aurait été invokevirtual au lieu de invokespecial; voir JLS §7.7 appel de Méthodes.)

Maintenant, comme je l'ai dit, je ne pense pas qu'il y ait une grande différence de performance entre ces deux, autre que le fait qu' invokestatic nécessite moins de bytecode. invokestatic et invokespecial devrait à la fois être légèrement plus rapide qu' invokevirtual, car ils utilisent tous les deux statique de la liaison au lieu de dynamique, mais je n'ai aucune idée si l'un est plus rapide que les autres. Je ne trouve pas de bonnes références. Le plus proche que je peux trouver est ce 1997 JavaWorld article, qui, fondamentalement, reformule ce que je viens de dire:

La manière la plus rapide des instructions seront vraisemblablement invokespecial et invokestatic, parce que les méthodes invoquées par ces instructions sont statiquement lié. Lorsque la JVM résout la référence symbolique pour ces instructions et la remplace par une référence directe, que la référence directe ne sera probablement inclure un pointeur vers le véritable bytecode.

Mais beaucoup de choses ont changé depuis 1997.

Donc, en conclusion... je suppose que je suis toujours coller avec ce que j'ai dit avant. La vitesse ne devrait pas être la raison de choisir l'un sur l'autre, car il s'agirait d'un micro-optimisation, au mieux.

18voto

Powerlord Points 43989

La réponse est ... cela dépend.

Si member est une variable d'instance spécifique à l'objet avec lequel vous traitez, alors pourquoi le passer en 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 */ } 
}
 

18voto

Steve B. Points 23227

Ma préférence personnelle serait de les déclarer statiques, car c'est un drapeau clair qu'ils sont apatrides.

11voto

oxbow_lakes Points 70013

Une des raisons pour lesquelles vous pourriez vouloir déclarer des méthodes statiques auxiliaires est si vous avez besoin de les appeler dans le constructeur de classe "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 ce cas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X