wake-up-neo.com

Sollten private Hilfsmethoden statisch sein, wenn sie statisch sein können?

Nehmen wir an, ich habe eine Klasse, die zur Instanziierung entwickelt wurde. Ich habe mehrere private "Helfer" -Methoden in der Klasse, die keinen Zugriff auf eines der Klassenmitglieder erfordern und nur mit ihren Argumenten arbeiten und ein Ergebnis zurückgeben.

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) {... } 
} 

Gibt es einen bestimmten Grund, computeOne und computeMore als statische Methoden anzugeben - oder einen bestimmten Grund, dies nicht zu tun?

Es ist mit Sicherheit am einfachsten, sie als nicht statisch zu belassen, obwohl sie mit Sicherheit statisch sein könnten, ohne Probleme zu verursachen.

194
avalys

Ich bevorzuge solche Hilfsmethoden als private static; Dadurch wird dem Leser klar, dass er den Zustand des Objekts nicht ändert. Mein IDE zeigt auch Aufrufe von statischen Methoden in Kursivschrift an, sodass ich weiß, dass die Methode statisch ist, ohne die Signatur zu betrachten.

166
Esko Luontola

Dies kann zu etwas kleinerem Bytecode führen, da die statischen Methoden keinen Zugriff auf this erhalten. Ich denke nicht, dass es einen Unterschied in der Geschwindigkeit macht (und wenn es so wäre, wäre es wahrscheinlich zu klein, um insgesamt einen Unterschied zu machen).

Ich würde sie statisch machen, da ich das im Allgemeinen mache, wenn es überhaupt möglich ist. Aber das bin nur ich.


EDIT: Diese Antwort wird immer wieder abgelehnt, möglicherweise wegen der unbegründeten Aussage über die Bytecode-Größe. Also werde ich tatsächlich einen Test durchführen.

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 (abgerufen mit 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

}

Das Aufrufen der statischen Methode erfordert zwei Bytecodes (Byteops?): iconst_0 (für das Argument) und invokestatic.
Das Aufrufen der nicht statischen Methode dauert drei: aload_1 (für das TestBytecodeSize Objekt, nehme ich an), iconst_0 (für das Argument) und invokespecial. (Beachten Sie, dass dies keine privaten Methoden gewesen wären, sondern invokevirtual statt invokespecial; siehe JLS §7.7 Methoden aufrufen .)

Nun, wie gesagt, erwarte ich keinen großen Leistungsunterschied zwischen diesen beiden, abgesehen von der Tatsache, dass invokestatic einen Bytecode weniger benötigt. invokestatic und invokespecial sollten beide etwas schneller als invokevirtual sein, da beide statische statt dynamische Bindungen verwenden, aber ich habe keine Ahnung, ob eine schneller als die andere ist. Ich kann auch keine guten Referenzen finden. Der nächste, den ich finden kann, ist dieser JavaWorld-Artikel von 1997 , der im Grunde das wiedergibt, was ich gerade gesagt habe:

Die schnellsten Anweisungen sind höchstwahrscheinlich invokespecial und invokestatic, da die von diesen Anweisungen aufgerufenen Methoden statisch gebunden sind. Wenn die JVM die symbolische Referenz für diese Anweisungen auflöst und durch eine direkte Referenz ersetzt, enthält diese direkte Referenz wahrscheinlich einen Zeiger auf die tatsächlichen Bytecodes.

Aber seit 1997 hat sich vieles geändert.

Also zum Schluss ... Ich glaube, ich bleibe immer noch bei dem, was ich vorher gesagt habe. Geschwindigkeit sollte nicht der Grund sein, eine über der anderen zu wählen, da dies bestenfalls eine Mikrooptimierung wäre.

107
Michael Myers

Meine persönliche Präferenz wäre es, sie als statisch zu deklarieren, da es eine klare Flagge ist, dass sie staatenlos sind.

18
Steve B.

Die Antwort ist ... es kommt darauf an.

Wenn member eine Instanzvariable ist, die spezifisch für das Objekt ist, mit dem Sie sich befassen, warum sollte sie dann überhaupt als Parameter übergeben werden?

Zum Beispiel:

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 */ } 
}
18
Powerlord

Möglicherweise möchten Sie statische Hilfsmethoden deklarieren, wenn Sie sie im Klassenkonstruktor "vor" this oder super aufrufen müssen. Beispielsweise:

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));
    }
}

Dies ist ein Beispiel, aber es ist klar, dass recoverInt in diesem Fall keine Instanzmethode sein kann.

11
oxbow_lakes

Ich kann mir keine klaren Vorteile für die private statische Methode vorstellen. Davon abgesehen hat es auch keine besonderen Vorteile, sie nicht statisch zu machen. Es ist hauptsächlich eine Frage der Präsentation: Vielleicht möchten Sie sie statisch machen, um deutlich zu machen, dass sie ein Objekt nicht verändern.

Für Methoden mit unterschiedlichen Zugriffsrechten gibt es meines Erachtens zwei Hauptargumente:

  • statische Methoden können aufgerufen werden, ohne eine Instanz eines Objekts zu erstellen, was nützlich sein kann
  • statische Methoden können nicht vererbt werden, was ein Problem sein kann, wenn Sie einen Polymorphismus benötigen (dies ist jedoch für private Methoden irrelevant).

Außerdem ist der Unterschied ziemlich gering, und ich bezweifle stark, dass der zusätzliche Zeiger, der an die Instanzmethode übergeben wird, einen signifikanten Unterschied ausmacht.

10
Axelle Ziegler

Die richtige Antwort lautet:

jede Methode, die keine Informationen aus einem Feld entnimmt und keine Informationen in ein Feld einfügt, muss keine Instanzmethode sein. Jede Methode, die keine Felder in ihrer Klasse oder ihrem Objekt verwendet oder ändert, kann auch eine statische Methode sein.

7
Gyan Singh

oder einen bestimmten Grund, sie nicht als statisch zu deklarieren?

Ja.

Indem Sie sie als Instanzmethoden beibehalten, können Sie später eine andere Implementierung bereitstellen.

Es mag albern klingen (und tatsächlich wäre es so, wenn diese Methoden nur von Ihnen in einem Programm mit 50 Zeilen verwendet würden), aber in größeren Anwendungen oder in Bibliotheken, die von jemand anderem verwendet werden, können Sie sich für eine bessere Implementierung entscheiden, aber nicht bestehenden Code knacken wollen.

Sie erstellen also eine Unterklasse und geben diese in den neuen Versionen zurück. Da die Methoden als Instanzmethoden deklariert wurden, lassen Sie den Polymorphismus einfach seine Aufgabe erledigen.

Darüber hinaus können Sie den Konstruktor privat machen und aus demselben Grund eine statische Factory-Methode bereitstellen.

Daher empfehle ich, sie als Instanzmethoden beizubehalten und statische Aufladung nach Möglichkeit zu vermeiden.
Nutzen Sie die Dynamik, die die Sprache bietet.

Sehen Sie sich hier ein etwas ähnliches Video an: Wie man eine gute API entwirft und warum es wichtig ist

Obwohl es nicht direkt mit der Methodendiskussion "Static vs Instance" zusammenhängt, werden einige interessante Punkte im API-Design angesprochen.

5
OscarRyz

Ein Problem bei statischen Methoden ist, dass die Verwendung des Objekts in Komponententests schwieriger wird. Mockito kann keine Mocks für statische Methoden erstellen und Sie können keine Unterklassenimplementierung der Methode erstellen.

5
Jon Onstott

Wenn es sich bei der Methode im Grunde genommen nur um eine Subroutine handelt, die Zustandsinformationen niemals vorhersehbar verwendet, deklarieren Sie sie als statisch.

Dies ermöglicht die Verwendung in anderen statischen Methoden oder bei der Klasseninitialisierung, d. H .:

public class Example {
   //...

   //Only possible if computeOne is static
   public final static double COMPUTED_ONE = computeOne(new Something("1"));

   //...
}
4
Kip

In solchen Fällen bevorzuge ich statische Methoden für computeOne und computeMore. Der Grund: Verkapselung. Je weniger Code Zugriff auf die Implementierung Ihrer Klasse hat, desto besser.

In dem von Ihnen angegebenen Beispiel geben Sie an, dass computeOne und computeMore nicht auf die Interna der Klasse zugreifen müssen. Geben Sie den Betreuern der Klasse daher die Möglichkeit, sich in die Interna einzumischen.

3
maxaposteriori

Ich möchte ein paar Dinge klarstellen, die andere Plakate gesagt haben, um falsche Informationen zu liefern.

Erstens, da die Methoden privat sind, auch wenn Sie sie als statisch deklarieren, können Sie außerhalb dieser Klasse nicht auf sie zugreifen. Zweitens sind sie privat, sodass Sie sie nicht einmal in Unterklassen überschreiben können, sodass statisch oder nicht statisch keinen Unterschied macht. Drittens kann eine nicht statische private Methode auch von einem Konstruktor der Klasse aufgerufen werden, sie muss nicht statisch sein.

Kommen wir nun zu Ihrer Frage, ob eine private Hilfsmethode als statisch oder nicht statisch definiert werden soll. Ich werde mit Steve's Antwort fortfahren, da das Markieren einer statischen privaten Methode zeigt, dass diese Methode zustandslos ist, da ich diese Regel auch beim Codieren befolge.

3

Aus der Erfahrung würde ich sagen, dass solche privaten Methoden eher universell und wiederverwendbar sind.

Ich denke, das erste, was zu tun ist, ist die Frage, ob die Methode außerhalb des aktuellen Klassenkontexts nützlich sein kann. In diesem Fall würde ich genau das tun, was Jeder vorschlägt, und diese Methode als statisch für eine Utils-Klasse extrahieren, die hoffentlich von jemandem überprüft wird, bevor eine neue Methode implementiert wird, die genau dasselbe tut.

Solche allgemein verwendeten privaten Methoden sind eine Quelle für einen Großteil der Codeduplizierung in Projekten, da jeder Entwickler sie unabhängig an der Stelle neu erfindet, an der er sie verwenden muss. Die Zentralisierung solcher Methoden ist also ein weiter Weg.

3
Piotr Sobczyk

Die statische/nicht statische Frage lautet: "Muss ich wirklich ein Objekt dieser Klasse verwenden?"

Übergeben Sie das Objekt also zwischen verschiedenen Methoden? Enthält das Objekt Informationen, die außerhalb des Kontexts der statischen Methoden nützlich sind? Gibt es einen Grund, Methoden nicht in beide Richtungen zu definieren, wenn Sie sie in beide Richtungen verwenden?

Wenn Sie sich in diesem Dilemma befinden, scheinen mir alle für die Methode erforderlichen Daten in Ihrem Code außerhalb des Objekts zu schweben. Ist das was du willst? Wäre es einfacher, diese Daten jedes Mal in einem Objekt zu sammeln? Sie sind möglicherweise nur ambivalent, wenn Sie sich auf ein einzelnes Modell festlegen. Wenn Sie alles auf eine Art und Weise erledigen können, wählen Sie entweder statisch oder nicht statisch und fahren Sie damit fort.

2
notnot

Insbesondere für das von Ihnen angegebene Beispiel scheint der Zweck der Definition dieser Methoden mehr der Klarheit des Codes beim Lesen als der Funktionalität zu dienen (sie sind als privat definiert). In diesem Fall bringt es Ihnen nichts, mit static zu arbeiten, da der Zweck von static darin besteht, die Klassenfunktionalität verfügbar zu machen.

2
notnot
class Whatever {

    public static varType myVar = initializeClassVariable();

    private static varType initializeClassVariable() {

        //initialization code goes here
    }
}

Der Vorteil von privaten statischen Methoden besteht darin, dass sie später wiederverwendet werden können, wenn Sie die Klassenvariable neu initialisieren müssen.

1
mug896

Ein Grund dafür ist, dass statische Methodenaufrufe bei sonst gleichen Bedingungen schneller sein sollten. Statische Methoden können nicht virtuell sein und nehmen diese Referenz nicht implizit an.

1
dsimcha
  1. Ohne den statischen Modifikator können Sie nicht herausfinden, dass die Methode ohne zusätzliche Analyse zustandslos ist, was beim (erneuten) Schreiben der Methode leicht möglich ist.

  2. Der Modifikator "static" gibt Ihnen möglicherweise Anregungen für das Refactoring, neben anderen Dingen, die andere möglicherweise als unbrauchbar empfinden. Z.B. Verschieben der Methode in eine Utility-Klasse oder Konvertieren in eine Member-Methode.

1
bodrin

Off-Topic: Ich würde die Hilfsmethoden in einer eigenständigen Hilfsprogramm-/Hilfsklasse behalten, die nur statische Methoden enthält.

Das Problem bei der Verwendung von Hilfsmethoden am Verwendungsort ("gleiche Klasse") besteht darin, dass jemand auf der ganzen Linie beschließt, seine eigenen, nicht verwandten Hilfsmethoden an derselben Stelle zu veröffentlichen

1
Everyone

Ich würde sie als statisch deklarieren, um sie als staatenlos zu kennzeichnen.

Java hat keinen besseren Mechanismus für kleinere Operationen, die nicht exportiert werden. Ich denke also, dass private statische Aufladung akzeptabel ist.

0
Uri

Wie viele Leute sagten, machen Sie es als statisch ! Hier ist die Faustregel, der ich folge: Wenn Sie glauben, die Methode ist nur eine mathematische Funktion , dh sie ist zustandslos, beinhaltet keine Instanzvariablen (=) > keine blauen Farbvariablen [in Eclipse] in der Methode), und das Ergebnis der Methode ist für 'n' Anzahl von Aufrufen (natürlich mit denselben Parametern) dasselbe. Markieren Sie dann diese Methode als STATIC.

Wenn Sie der Meinung sind, dass diese Methode für andere Klassen nützlich ist, verschieben Sie sie andernfalls in eine Util-Klasse, und fügen Sie die Methode als privat in die gleiche Klasse ein. (Minimierung der Zugänglichkeit)

0
jai