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

205

Angenommen, ich habe eine Klasse, die instanziiert werden soll. Ich habe mehrere private "Hilfs" -Methoden innerhalb der Klasse, die keinen Zugriff auf eines der Klassenmitglieder erfordern, und arbeite ausschließlich mit ihren Argumenten und gebe ein Ergebnis zurück.

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 angeben computeOneund computeMoreals statische Methoden - oder einen bestimmten Grund nicht zu tun?

Es ist sicherlich am einfachsten, sie als nicht statisch zu belassen, obwohl sie ohne Probleme statisch sein können.

Lawinen
quelle
3
Siehe auch, wenn das Schlüsselwort static in Java nicht verwendet werden soll: stackoverflow.com/questions/1766715/…
Mark Butler

Antworten:

174

Ich bevorzuge solche Hilfsmethoden private static; Dadurch wird dem Leser klar, dass er den Status des Objekts nicht ändert. Meine IDE zeigt auch Aufrufe statischer Methoden in Kursivschrift an, sodass ich weiß, dass die Methode statisch ist, ohne auf die Signatur zu achten.

Esko Luontola
quelle
2
Einer meiner Lieblingsthreads. Ich verwende NetBeans und es werden statische Methodenaufrufe mit kursiven Schriftarten angezeigt.
Skiabox
2
Normalerweise deklariere ich protected staticdiese Hilfsmethoden als solche, die sie in einer Testklasse im selben Paket sehr einfach testbar machen.
James
2
@ James oder einfach static(wenn wir es nur zum Testen wollen).
Mrod
3
"Ändert den Status des Objekts nicht" - perfekte Erklärung, wie man es von einer privaten Methode unterscheidet.
HopeKing
110

Dies kann zu einem etwas kleineren Bytecode führen, da die statischen Methoden keinen Zugriff erhalten this. 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 dies im Allgemeinen tue, wenn es überhaupt möglich ist. Aber das bin nur ich.


BEARBEITEN: Diese Antwort wird immer wieder abgelehnt, möglicherweise aufgrund der unbegründeten Behauptung ü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 erfordert drei: aload_1(für das TestBytecodeSizeObjekt, nehme ich an), iconst_0(für das Argument) und invokespecial. (Beachten Sie, dass, wenn dies keine privaten Methoden gewesen wären, dies invokevirtualstattdessen gewesen wäre invokespecial; siehe JLS §7.7 Aufrufen von Methoden .)

Nun, wie gesagt, ich erwarte keinen großen Leistungsunterschied zwischen diesen beiden, abgesehen von der Tatsache, invokestaticdass ein Bytecode weniger erforderlich ist. invokestaticund invokespecialsollten beide etwas schneller sein als invokevirtual, da beide statische Bindung anstelle von dynamischer verwenden, aber ich habe keine Ahnung, ob einer schneller als der andere ist. Ich kann auch keine guten Referenzen finden. Der nächstgelegene, den ich finden kann, ist dieser JavaWorld-Artikel von 1997 , in dem im Grunde das wiederholt wird, was ich gerade gesagt habe:

Die schnellsten Anweisungen sind höchstwahrscheinlich invokespecialund 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 haben sich viele Dinge geändert.

Also abschließend ... Ich denke, ich bleibe immer noch bei dem, was ich vorher gesagt habe. Geschwindigkeit sollte nicht der Grund sein, sich für eine andere zu entscheiden, da dies bestenfalls eine Mikrooptimierung wäre.

Michael Myers
quelle
all diese negativen Stimmen für eine scheinbar sehr einfache Antwort. +1 im Interesse der Wahrheit, Gerechtigkeit, ....
Steve B.
Vielen Dank. (Obwohl ich es hätte löschen und ein Abzeichen bekommen können, während es um -3 war .: D)
Michael Myers
2
Der JIT-Compiler wird sie sowieso inline und optimieren, sodass die Anzahl der Bytecode-Anweisungen wenig damit zu tun hat, wie schnell sie sein werden.
Esko Luontola
3
Deshalb sagte ich: "Ich glaube 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)."
Michael Myers
7
Bevor Sie solche Mikrooptimierungen vornehmen, sollten Sie die Auswirkungen des Hot-Spot-Compilers berücksichtigen. Fazit: Schreiben Sie Ihren Code für die Lesbarkeit durch Menschen und überlassen Sie die Optimierung dem Compiler
Ichthyo
18

Meine persönliche Präferenz wäre es, sie für statisch zu erklären, da es eine klare Flagge ist, dass sie zustandslos sind.

Steve B.
quelle
18

Die Antwort ist ... es kommt darauf an.

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

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 */ } 
}
Powerlord
quelle
5
+1: Obwohl das Beispiel schlecht ist, sind zu viele Methoden, die statisch sein KÖNNTEN, ein schlechter Codegeruch. Übrigens sind statische Methoden eigentlich Funktionen, sie sind überhaupt nicht OO. Sie können als Methode in eine andere Klasse gehören, oder Sie vermissen möglicherweise eine Klasse, zu der diese Funktion als Methode gehören könnte.
Bill K
11

Ein Grund, warum Sie möglicherweise statische Hilfsmethoden deklarieren möchten, besteht darin, dass Sie sie im Klassenkonstruktor "vor" thisoder "aufrufen" müssen super. 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 erfundenes Beispiel, recoverIntkann aber in diesem Fall eindeutig keine Instanzmethode sein.

oxbow_lakes
quelle
Sie können eine Instanzmethode im Konstruktor aufrufen. Wenn Sie jedoch mit super (...) oder this (...) an einen anderen Konstruktor delegieren, können Sie eine Instanzmethode erst nach der Delegierung aufrufen (statische Daten jedoch) ok, wie Sie darauf hinweisen)
Kip
10

Ich kann mir keine klaren Vorteile für die private statische Methode vorstellen. Abgesehen davon gibt es auch keine besonderen Vorteile, wenn sie nicht statisch sind. 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 Polymorphismus benötigen (ist aber für private Methoden irrelevant).

Abgesehen davon ist der Unterschied ziemlich gering, und ich bezweifle stark, dass das Extra, das dieser Zeiger an die Instanzmethode übergeben hat, einen signifikanten Unterschied macht.

Axelle Ziegler
quelle
4
Der Vorteil, es nicht statisch zu machen, besteht darin, dass jemand das Verhalten der Methode unterordnen und überschreiben kann.
Clint Miller
7
Clint ist eine private Methode, sodass Sie die Methode nicht überschreiben können.
Bhushan Bhangale
Genau, für private Methoden denke ich nicht, dass es einen großen Unterschied macht. Für öffentliche Methoden stimme ich jedoch dem zu, was Sie sagen
Axelle Ziegler
8

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.

Gyan Singh
quelle
5

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, wenn diese Methoden nur von Ihnen in einem 50-Zeilen-Programm verwendet werden), 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 möchte vorhandenen Code brechen.

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 davon profitieren, den Konstruktor privat zu machen und aus demselben Grund eine statische Factory-Methode bereitzustellen.

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

Hier finden Sie ein etwas verwandtes Video: Wie man eine gute API entwirft und warum es wichtig ist

Obwohl es nicht direkt mit der Diskussion der Methode "statisch gegen Instanz" zusammenhängt, werden einige interessante Punkte im API-Design angesprochen.

OscarRyz
quelle
1
Stimme voll und ganz zu. Normalerweise versuche ich aus genau diesem Grund, Statik und Privaten insgesamt zu vermeiden. Ich denke, dass die meisten anderen Antworten den Punkt verfehlt haben.
Clint Miller
22
Wir sprechen von privaten Helfern, was bedeutet, dass sie nicht Teil der öffentlichen API der Klasse sind. Das bedeutet, dass nichts Sie daran hindert, später eine andere Implementierung bereitzustellen, diese nicht statisch zu machen oder andere Änderungen vorzunehmen.
Jonik
Aaaahmm ... das ist ein guter Punkt, Jonik. Dennoch sollte es Grund genug sein, eine gute Angewohnheit zu schaffen (subjektiv gesehen natürlich)
OscarRyz
2
Stimme überhaupt nicht zu. Es gibt keinen guten Grund, eine private Methode zu ändern, ohne die Klasse zu ändern, in der sie definiert ist. Die einzige Möglichkeit, das zu tun, was Sie vorschlagen, ist die Manipulation des Bytecodes.
Peter Lawrey
2
Was Sie vorschlagen, könnte sinnvoll sein, wenn die Methode nicht privat wäre, aber selbst dann würde ich vorschlagen, dass Sie auf der Grundlage eines benötigten Stroms entwerfen, anstatt auf der Grundlage eines imaginären Bedarfs zu entwerfen.
Peter Lawrey
5

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

Jon Onstott
quelle
2
Sie sollten keine Tests für private Methoden schreiben. Siehe hier . Es ist nicht erforderlich, eine private Methode zu testen, ob sie statisch ist oder nicht.
BW
@BW Das ist eine sehr subjektive Sache. Es gibt viele triftige Gründe, eine private Methode zu testen.
Ruohola
4

Wenn die Methode im Grunde nur eine Unterroutine ist, die niemals vorhersehbar Statusinformationen verwendet, deklarieren Sie sie als statisch.

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

public class Example {
   //...

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

   //...
}
Pennen
quelle
3

Meine Präferenz in Fällen wie diesen zu machen computeOneund computeMorestatische Methoden. Der Grund: Kapselung. Je weniger Code Zugriff auf die Implementierung Ihrer Klasse hat, desto besser.

In dem Beispiel, das Sie geben, geben Sie an, dass Sie nicht auf die Interna der Klasse zugreifen müssen computeOneund computeMoresollten. Warum sollten Sie also den Betreuern der Klasse die Möglichkeit geben, sich in die Interna einzumischen?

maxaposteriori
quelle
3

Ich möchte einige Dinge klarstellen, die andere Plakate als falsche Informationen bezeichnet haben.

Erstens können Sie außerhalb dieser Klasse nicht auf sie zugreifen, da die Methoden privat sind, auch wenn Sie sie als statisch deklarieren. Zweitens sind sie privat, sodass Sie sie nicht einmal in der Unterklasse ü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 Steves Antwort fortfahren, da das Markieren einer statischen privaten Methode zeigt, dass diese Methode zustandslos ist, da ich diese Regel auch beim Codieren befolge.

Bhushan Bhangale
quelle
Aber es gibt Orte, an denen nur eine statische Methode aufgerufen werden kann, wie in meinem Beispiel und in Chris Marshalls Beispiel
Kip
Ja Kip deine und Chris Antworten sind richtig. Ich habe diese nicht kommentiert, da es sich um richtige Antworten handelt. Ich habe nur über falsche Antworten gesprochen.
Bhushan Bhangale
3

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

Ich denke, das erste, was zu tun ist, ist die Frage zu stellen, ob die Methode außerhalb des aktuellen Klassenkontexts nützlich sein kann. Wenn ja, würde ich genau das tun, was jeder vorschlägt, und diese Methode als statisch für eine Utils-Klasse extrahieren, in der hoffentlich jemand prüft, bevor er eine neue Methode implementiert, die genau dasselbe tut.

Solche allgemein verwendeten privaten Methoden sind die Quelle eines großen Teils der Codeduplizierung im Projekt, da jeder Entwickler sie unabhängig neu erfindet, genau an der Stelle, an der er sie verwenden muss. Die Zentralisierung solcher Methoden ist also ein langer Weg.

Piotr Sobczyk
quelle
2

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, scheint es mir, dass Sie alle Daten, die für die Methode erforderlich sind, in Ihrem Code außerhalb des Objekts haben. 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 Weise erledigen können, wählen Sie entweder statisch oder nicht statisch und fahren Sie fort.

nicht nicht
quelle
2

Insbesondere in dem von Ihnen angegebenen Beispiel scheint der Zweck der Definition dieser Methoden eher der Klarheit des Codes beim Lesen als der Funktionalität zu dienen (sie sind als privat definiert). In diesem Fall bringt die Verwendung von static nichts für Sie, da der Zweck von static darin besteht, die Klassenfunktionalität verfügbar zu machen.

nicht nicht
quelle
Diese kleine Antwort, die unter einer Menge anderer Antworten verborgen ist, berührt wirklich das Wesentliche: Funktionalität auf Klassenebene vs. Funktionalität auf Objektebene.
Eljenso
Danke, el, ich weiß das wirklich zu schätzen. Ich hätte auch nichts dagegen, ein wenig abzustimmen :)
nicht
Ich habe es zu dem Zeitpunkt, als ich den Kommentar schrieb, mit +1 bewertet.
Eljenso
1
Ich bin nicht einverstanden. Die Klarheit des Codes ist für private Methoden immer noch wichtig. Es mag weniger wichtig sein, aber es ist immer noch etwas, nach dem man streben muss.
LegendLength
1

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

Dsimcha
quelle
Siehe meine Antwort unten (ich habe die Analyse hinzugefügt, nachdem sie bereits bei -3 lag, daher ist sie nicht sehr sichtbar).
Michael Myers
1

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

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

jai
quelle
1

Off-Topic: Ich würde die Hilfsmethoden in einer eigenständigen Dienstprogramm- / Hilfsklasse mit nur statischen Methoden behalten.

Das Problem mit Hilfsmethoden am Verwendungsort (lesen Sie "gleiche Klasse") besteht darin, dass sich jemand auf der ganzen Linie möglicherweise dafür entscheidet, seine eigenen nicht verwandten Hilfsmethoden an derselben Stelle zu veröffentlichen

Jeder
quelle
-1: SO ist kein Messaging-Forum. Sie werden es besser machen, wenn Sie tatsächlich eine richtige Frage stellen.
Stu Thompson
1
Ich würde es vorziehen, die Hilfsmethoden zusammen mit der Klasse, mit der sie verbunden sind, als statische zu haben. Darüber hinaus kann ich einige als öffentlich zugänglich machen, wenn sie extern verwendet werden sollen. Auf diese Weise ist es einfacher, die API für diese Klasse zu verwalten, wenn sie öffentlich zugänglich gemacht und intensiv genutzt werden soll.
Ivaylo Slavov
1
class Whatever {

    public static varType myVar = initializeClassVariable();

    private static varType initializeClassVariable() {

        //initialization code goes here
    }
}

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

mug896
quelle
1
  1. Ohne den statischen Modifikator können Sie ohne zusätzliche Analyse nicht herausfinden, dass die Methode zustandslos ist. Dies ist einfach, wenn Sie die Methode (neu) schreiben.

  2. Dann kann der "statische" Modifikator Ihnen neben anderen Dingen, die andere möglicherweise als nutzlos empfinden, Ideen zum Refactoring geben. ZB Verschieben der Methode in eine Utility-Klasse oder Konvertieren in eine Member-Methode.

Bodrin
quelle
0

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

Java hat keinen besseren Mechanismus für kleinere Operationen, die nicht exportiert werden. Daher halte ich private statische Aufladungen für akzeptabel.

Uri
quelle