Czy prywatne metody pomocnicze powinny być statyczne, jeśli mogą być statyczne

Powiedzmy, że mam klasę zaprojektowaną do utworzenia instancji. Mam kilka prywatnych "pomocniczych" metod wewnątrz klasy, które nie wymagają dostępu do żadnego z członków klasy i działają wyłącznie na ich argumentach, zwracając wynik.

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

Czy Jest jakiś szczególny powód, aby określić computeOne i computeMore jako metody statyczne - lub jakiś szczególny powód, aby tego nie robić?

Z pewnością najłatwiej jest pozostawić je jako niestatyczne, mimo że z pewnością mogą być statyczne bez powodowania żadnych problemy.
Author: Raedwald, 2009-02-12

21 answers

Preferuję takie metody pomocnicze private static; które wyjaśnią czytelnikowi, że nie zmienią stanu obiektu. Moje IDE pokaże również wywołania do metod statycznych kursywą, więc będę wiedział, że metoda jest statyczna bez patrzenia na podpis.

 154
Author: Esko Luontola,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-06 05:23:08

Może to spowodować nieco mniejszy bajt kodu, ponieważ statyczne metody nie uzyskają dostępu do this. Nie sądzę, aby to miało jakiekolwiek znaczenie w prędkości (a gdyby tak było, prawdopodobnie byłoby zbyt małe, aby ogólnie coś zmienić).

Uczyniłbym je statycznymi, ponieważ generalnie robię to, jeśli w ogóle jest to możliwe. Ale to tylko ja.


EDIT: ta odpowiedź jest ciągle zawyżana, prawdopodobnie z powodu bezpodstawnego twierdzenia o rozmiarze bajtu. Więc będę zrób 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 (pobrany z 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

}

Wywołanie metody statycznej pobiera dwa bajtody (bajtops?): iconst_0 (dla argumentu) i invokestatic.
Wywołanie niestatycznej metody zajmuje trzy: aload_1 (dla obiektu TestBytecodeSize, jak przypuszczam), iconst_0 (dla argumentu) i invokespecial. (Zauważ, że gdyby nie były to metody prywatne, byłoby to invokevirtual zamiast invokespecial; Zobacz JLS §7.7 wywoływanie metod .)

Teraz, jak powiedziałem, nie oczekuję, że tam być jakąkolwiek wielką różnicą w wydajności między tymi dwoma, poza faktem, że invokestatic wymaga o jeden bajt kodu mniej. invokestatic i invokespecial powinny być nieco szybsze niż invokevirtual, ponieważ oba używają wiązania statycznego zamiast dynamicznego, ale nie mam pojęcia, czy jedno z nich jest szybsze od drugiego. Nie mogę znaleźć żadnych dobrych referencji. Najbliższy, jaki mogę znaleźć, to Ten artykuł JavaWorld z 1997 roku , który w zasadzie powtarza to, co właśnie powiedziałem:

Najszybsze instrukcje będą najbardziej prawdopodobnie invokespecial i invokestatic, ponieważ metody wywoływane przez te instrukcje są statycznie związane. Gdy JVM rozwiązuje symboliczne odniesienie dla tych instrukcji i zastąpi je bezpośrednim odniesieniem, to bezpośrednie odniesienie prawdopodobnie będzie zawierało wskaźnik do rzeczywistych bajtowych kodów.

Ale wiele się zmieniło od 1997 roku. Podsumowując... Chyba nadal trzymam się tego, co powiedziałem wcześniej. Prędkość nie powinna być powodem do wyboru jednego nad drugim, ponieważ w najlepszym razie byłaby to mikro-optymalizacja.
 103
Author: Michael Myers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-12 15:34:59

Moim osobistym preferowaniem byłoby zadeklarowanie ich statycznych, ponieważ jest to wyraźna flaga, że są bezpaństwowcami.

 17
Author: Steve B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:30:56

Odpowiedź brzmi:.. to zależy.

Jeśli member jest zmienną instancji specyficzną dla obiektu, z którym masz do czynienia, to po co w ogóle przekazywać ją jako parametr?

Na przykład:

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 */ } 
}
 17
Author: Powerlord,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:55:55

Jednym z powodów, dla których warto zadeklarować statyczne metody pomocnicze, jest konieczność wywołania ich w konstruktorze klasy "before" this lub super. Na przykład:

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

Jest to nieco wymyślony przykład, ale najwyraźniej recoverInt nie może być metodą instancji w tym przypadku.

 11
Author: oxbow_lakes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-12 08:05:08

Nie mogę myśleć o wyraźnych zaletach prywatnej metody statycznej. Biorąc to pod uwagę, nie ma żadnych szczególnych zalet, aby uczynić je niestatycznymi. To przede wszystkim kwestia prezentacji : być może warto uczynić je statycznymi, aby wyraźnie podkreślić fakt, że nie zmieniają obiektu.

Dla metody z różnymi uprawnieniami dostępu, myślę, że są dwa główne argumenty:

  • statyczne metody można wywoływać bez tworzenia instancji obiektu, która może być przydatne
  • metody statyczne nie mogą być dziedziczone, co może być problemem, jeśli potrzebujesz polimorfizmu (ale nie ma znaczenia dla metod prywatnych).

Poza tym różnica jest dość mała i mocno wątpię, czy dodatkowy wskaźnik przekazany do metody instancji ma znaczenie.

 10
Author: Axelle Ziegler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:35:00

Poprawna odpowiedź to:

Każda metoda, która nie pobiera żadnych informacji z pola i nie umieszcza żadnych informacji w polu, nie musi być metodą instancyjną. Każda metoda, która nie używa ani nie zmienia żadnych pól w swojej klasie lub obiekcie, równie dobrze może być metodą statyczną.

 7
Author: Gyan Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-05 13:00:24

czy jakiś szczególny powód, aby nie [deklarować ich jako statycznych]?

Tak.

Zachowując je jako metody instancji, pozwalasz sobie na dostarczenie później innej implementacji.

Może to zabrzmieć głupio (i tak by było, gdyby te metody były używane tylko przez Ciebie w 50-liniowym programie), ale w większych aplikacjach lub bibliotekach używanych przez kogoś innego możesz zdecydować się na lepszą implementację, ale nie chcesz niszczyć istniejących kod.

Więc tworzysz podklasę i zwracasz ją w nowych wersjach, a ponieważ metody zostały zadeklarowane jako metody instancji, pozwalasz polimorfizmowi wykonać swoje zadanie.

Dodatkowo, z tego samego powodu możesz skorzystać na uczynieniu konstruktora prywatnym i udostępnić statyczną metodę fabryczną.

Więc, moim zaleceniem jest, aby zachować je jako metody instancji i unikać statycznych, jeśli to możliwe.
Skorzystaj z dynamizmu, jaki zapewnia język.

Zobacz tutaj nieco pokrewny film: Jak zaprojektować dobre API i dlaczego to ma znaczenie

Chociaż nie jest to bezpośrednio związane z dyskusją metody "static vs instance", dotyka ona kilku interesujących punktów w projektowaniu API.

 5
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-08 18:00:58

Jeśli metoda jest w zasadzie tylko podprogramem, który nigdy nie będzie przewidywał użycia informacji o stanie, zadeklaruj ją jako statyczną.

Pozwala to na użycie go w innych metodach statycznych lub w inicjalizacji klasy, np.:

public class Example {
   //...

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

   //...
}
 4
Author: Kip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:43:30

Problem dotyczący posiadania metod statycznych polega na tym, że może to utrudnić użycie obiektu w testach jednostkowych . Mockito nie może tworzyć mocków dla metod statycznych i nie można utworzyć podklasy implementacji metody.

 4
Author: Jon Onstott,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-25 14:02:26

W takich przypadkach preferuję metody statyczne computeOne i computeMore. Powód: enkapsulacja. Im mniej kodu, który ma dostęp do implementacji twojej klasy, tym lepiej.

W podanym przykładzie stwierdzasz, że computeOne i computeMore nie powinny mieć dostępu do wewnętrznych elementów klasy, więc po co dawać opiekunom klasy możliwość mieszania się z wewnętrznymi.

 3
Author: maxaposteriori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:48:08

Chciałbym wyjaśnić kilka rzeczy, które Inne plakaty powiedziały jako jego podając błędne informacje.

Po pierwsze, ponieważ metody są prywatne, nawet jeśli zadeklarujesz je jako statyczne, nie będziesz mógł uzyskać do nich dostępu poza tą klasą. Po drugie są prywatne, więc nie można nawet nadpisać w podklasie, więc statyczne lub niestatyczne nie robi żadnej różnicy. Po trzecie niestatyczna prywatna metoda może być wywołana z konstruktora klasy również, nie musi być statyczna.

Teraz nadchodzi na twoje pytanie, czy prywatna metoda pomocnicza powinna być zdefiniowana jako statyczna lub niestatyczna. Pójdę z odpowiedzią Steve ' a jako oznaczanie prywatnej metody static pokazuje, że ta metoda jest bezpaństwowa, ponieważ również przestrzegam tej zasady podczas kodowania.

 3
Author: Bhushan Bhangale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-12 04:20:31

Statyczne / niestatyczne pytanie sprowadza się do "Czy naprawdę muszę używać obiektu tej klasy"?

Czy przekazujesz obiekt między różnymi metodami? Czy obiekt zawiera informacje przydatne poza kontekstem metod statycznych? Czy jest jakiś powód, aby nie definiować metod w obie strony, jeśli będziesz ich używać w obie strony?

Jeśli jesteś w tym dylemacie, wydaje mi się, że masz wszystkie dane wymagane do metody pływające w kodzie poza obiekt. Tego chcesz? Czy łatwiej byłoby zawsze zbierać te dane do obiektu za każdym razem? Możesz być po prostu ambiwalentny, jeśli chodzi o oddanie się jednemu modelowi. Jeśli możesz zrobić to wszystko w jeden sposób, wybierz statyczny lub niestatyczny i idź z nim.

 2
Author: notnot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:34:33

Mówiąc dokładniej o podanym przykładzie, wydaje się, że celem zdefiniowania tych metod jest bardziej przejrzystość kodu podczas czytania go niż funkcjonalność ( zdefiniowane jako prywatne). W takim przypadku, korzystanie z static naprawdę nic dla Ciebie nie robi, ponieważ static ma na celu ujawnienie funkcjonalności klas.

 2
Author: notnot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:39:30

Z doświadczenia chciałbym stwierdzić, że takie prywatne metody są dość uniwersalne i wielokrotnego użytku.

Myślę, że pierwszą rzeczą do zrobienia jest pytanie, czy metoda może być przydatna poza bieżącym kontekstem klasy. Jeśli tak, zrobiłbym dokładnie to, co wszyscy sugerują i wyodrębnił tę metodę jako statyczną do jakiejś klasy utils, gdzie ktoś miejmy nadzieję sprawdza przed wdrożeniem nowej metody robiącej dokładnie to samo.

Takie metody ogólnego użytku są źródłem dużych część duplikacji kodu w projekcie, ponieważ każdy programista samodzielnie odkrywa je właśnie w miejscu, w którym musi z niego korzystać. Tak więc centralizacja takich metod jest drogą do zrobienia.

 2
Author: Piotr Sobczyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-07 07:10:47

Jednym z powodów jest to, że wszystkie inne są równe, statyczne wywołania metod powinny być szybsze. Metody statyczne nie mogą być wirtualne i nie przyjmują implicite tego odniesienia.

 1
Author: dsimcha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-23 14:35:38

Off-Topic: trzymałbym metody pomocnicze w samodzielnej klasie narzędzi/helper z tylko statycznymi metodami.

Problem z posiadaniem metod pomocniczych w punkcie użycia (czyt. 'ta sama klasa' ) polega na tym, że ktoś w dół linii może po prostu wybrać umieszczenie własnych niepowiązanych metod pomocniczych w tym samym miejscu

 1
Author: Everyone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-25 06:29:42
class Whatever {

    public static varType myVar = initializeClassVariable();

    private static varType initializeClassVariable() {

        //initialization code goes here
    }
}

Zaletą prywatnych metod statycznych jest to, że można je później ponownie wykorzystać, jeśli trzeba ponownie zainicjować zmienną klasy.

 1
Author: mug896,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-06 11:19:47
  1. Bez modyfikatora statycznego nie można dowiedzieć się, że metoda jest bezpaństwowa bez dodatkowej analizy, która może być łatwo wykonana podczas (ponownego) pisania metody.

  2. Wtedy modyfikator" static " może dać ci pomysły na refaktoryzację poza innymi rzeczami, które inni mogą uznać za nieodpowiednie. Np. przeniesienie metody do jakiejś klasy użytkowej lub przekształcenie jej w metodę prętową..

 1
Author: bodrin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-25 07:07:55

Zadeklarowałbym je jako statyczne, aby oznaczyć je jako bezpaństwowe.

Java nie ma lepszego mechanizmu dla drobnych operacji, które nie są eksportowane, więc myślę, że prywatna statyczna jest akceptowalna.

 0
Author: Uri,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-11 21:51:38

Jak wiele osób powiedziało, zrób to jako static! Oto zasada kciuka, którą kieruję się : jeśli uważasz, że metoda jest tylko funkcją matematyczną tzn. jest bezpaństwowa, nie zawiera żadnych zmiennych instancji (=>Brak zmiennych koloru niebieskiego [w eclipse] w metodzie), a wynik metody będzie taki sam dla ' n ' liczby wywołań( oczywiście z tymi samymi parametrami), zaznacz tę metodę jako statyczną.

I jeśli uważasz, że ta metoda będzie przydatna do inna klasa następnie przenieś ją do klasy Util, w przeciwnym razie umieść metodę jako prywatną w tej samej klasie. (minimalizacja dostępności)

 0
Author: jai,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-25 05:57:31