Ostatnio przeglądałem swoje ostrzeżenia w Eclipse i natknąłem się na to:
Wyśle ostrzeżenie kompilatora, jeśli metodę można zadeklarować jako statyczną.
[edytuj] Dokładny cytat w pomocy Eclipse, z naciskiem na prywatne i końcowe:
Po włączeniu kompilator wyświetli błąd lub ostrzeżenie dla metod, które są prywatne lub ostateczne i które odnoszą się tylko do statycznych elementów członkowskich.
Tak, wiem, że mogę to wyłączyć, ale chcę poznać powód jego włączenia?
Dlaczego warto zadeklarować każdą możliwą metodę jako statyczną?
Czy da to jakieś korzyści związane z wydajnością? (w domenie mobilnej)
Wskazanie metody jako statycznej, jak przypuszczam, pokazuje, że nie używasz żadnych zmiennych instancji, dlatego można je przenieść do klasy stylu narzędzi?
Na koniec dnia powinienem po prostu wyłączyć to „ignoruj”, czy też powinienem naprawić ponad 100 ostrzeżeń, które mi dało?
Czy uważasz, że to tylko dodatkowe słowa kluczowe, które brudzą kod, ponieważ kompilator i tak po prostu wstawi te metody? (tak jakbyś nie deklarował każdej zmiennej, którą możesz sfinalizować, ale możesz ).
źródło
Odpowiedzi:
Za każdym razem, gdy piszesz metodę, realizujesz kontrakt w danym zakresie. Im węższy zakres, tym mniejsza szansa, że napiszesz błąd.
Gdy metoda jest statyczna, nie można uzyskać dostępu do niestatycznych elementów członkowskich; stąd twój zakres jest węższy. Jeśli więc nie potrzebujesz i nigdy nie będziesz potrzebować (nawet w podklasach) niestatycznych elementów członkowskich do wypełnienia kontraktu, po co dawać dostęp do tych pól swojej metodzie? Zadeklarowanie metody
static
w tym przypadku pozwoli kompilatorowi sprawdzić, czy nie używasz elementów członkowskich, których nie zamierzasz używać.Co więcej, pomoże to osobom czytającym Twój kod zrozumieć charakter umowy.
Dlatego dobrze jest zadeklarować metodę,
static
gdy faktycznie implementuje kontrakt statyczny.W niektórych przypadkach twoja metoda oznacza tylko coś odnoszącego się do instancji twojej klasy i zdarza się, że jej implementacja w rzeczywistości nie używa żadnego niestatycznego pola lub instancji. W takich przypadkach nie oznaczałbyś metody
static
.Przykłady sytuacji, w których nie można użyć
static
słowa kluczowego:źródło
private
metoda może być zadeklarowana jako statyczna, to prawie zawsze tak powinno być. W przypadku każdego innego poziomu dostępu należy wziąć pod uwagę inne czynniki, takie jak dynamiczna wysyłka.object.method()
wyboru metody do wywołania.Nie ma tutaj koncepcji z optymalizacją.
static
Metodastatic
, ponieważ wyraźnie oświadczyć, że metoda nie polega na dowolnej instancji klasy załączając tylko dlatego, że nie ma takiej potrzeby. Więc to ostrzeżenie Eclipse, jak podano w dokumentacji:Jeśli nie potrzebujesz żadnej zmiennej instancji, a Twoja metoda jest prywatna (nie można jej wywołać z zewnątrz) lub ostateczna (nie można jej nadpisać), nie ma powodu, aby była to zwykła metoda zamiast metody statycznej. Metoda statyczna jest z natury bezpieczniejsza, nawet dlatego, że możesz z nią zrobić mniej rzeczy (nie wymaga ona żadnej instancji, nie masz żadnego ukrytego
this
obiektu).źródło
Nie mam informacji na temat wydajności, przypuszczam, że jest co najwyżej nieznacznie lepsza, ponieważ kod nie musi wykonywać dynamicznego wysyłania na podstawie typu.
Jednak znacznie silniejszym argumentem przeciwko refaktoryzacji do metod statycznych jest to, że obecnie używanie statyczne jest uważane za złą praktykę. Metody / zmienne statyczne nie integrują się dobrze z językiem zorientowanym obiektowo, a także są trudne do poprawnego przetestowania. To jest powód, dla którego niektóre nowsze języki całkowicie rezygnują z koncepcji statycznych metod / zmiennych lub próbują internalizować je w języku w sposób, który lepiej współgra z obiektami obiektowymi (np. Obiekty w Scali).
W większości przypadków do implementacji funkcji, które używają parametrów jako danych wejściowych i generują dane wyjściowe (np. Funkcje narzędziowe / pomocnicze), potrzebne są statyczne metody, które pozwalają na to w językach współczesnych. nie jest potrzebne. Java 8 będzie miała zintegrowane wyrażenia lambda, więc już idziemy w tym kierunku.
źródło
private static
metody, więc nie będziesz musiał z nich kpić1. Metoda deklaracji
static
daje niewielką korzyść wydajnościową, ale co jest bardziej przydatne, pozwala na użycie go bez posiadania instancji obiektu pod ręką (pomyślmy na przykład o metodzie fabrycznej lub uzyskaniu singletona). Służy również dokumentacyjnemu określeniu natury metody. Ten cel dokumentacyjny nie powinien być ignorowany, ponieważ daje natychmiastową wskazówkę o naturze metody czytelnikom kodu i użytkownikom API, a także służy jako narzędzie myślenia dla oryginalnego programisty - wyraźne określenie zamierzonego znaczenia pomaga Ty też myślisz trzeźwo i tworzysz kod lepszej jakości (myślę na podstawie własnego doświadczenia, ale ludzie są różni). Na przykład jest logiczne i dlatego pożądane jest rozróżnienie między metodami operującymi na typie i metodami działającymi na instancji typu (jak wskazano wJon Skeet w komentarzu do pytania w języku C # ).Jeszcze innym przypadkiem użycia
static
metod jest naśladowanie interfejsu programowania proceduralnego. Myśleć ojava.lang.System.println()
klasie oraz zawartych w niej metodach i atrybutach. Klasajava.lang.System
jest używana jako przestrzeń nazw grupowania, a nie obiekt, który można utworzyć.2. jaki sposób Eclipse (lub jakikolwiek inny zaprogramowany lub inny rodzaj - biokompozowalny lub niebiokompozowalny - podmiot) może wiedzieć na pewno, która metoda może być zadeklarowana jako statyczna? Nawet jeśli klasa bazowa nie uzyskuje dostępu do zmiennych instancji lub nie wywołuje metod niestatycznych, mechanizm dziedziczenia może to zmienić. Tylko wtedy, gdy metody nie można przesłonić przez dziedziczenie podklasy, możemy stwierdzić ze 100% pewnością, że metoda rzeczywiście może zostać zadeklarowana
static
. Przesłonięcie metody jest niemożliwe dokładnie w dwóch przypadkach bytuprivate
(żadna podklasa nie może go używać bezpośrednio i nawet w zasadzie o tym nie wie) lubfinal
(nawet jeśli jest dostępna dla podklasy, nie ma możliwości zmiany metody odwoływania się do danych lub funkcji instancji).Stąd logika opcji Eclipse.
3. Oryginalny plakat zawiera również pytanie: „ Wskazanie metody jako statycznej, jak przypuszczam, pokazuje, że nie używasz żadnych zmiennych instancji, dlatego można by je przenieść do klasy stylu narzędzi? ” To bardzo dobra uwaga. Czasami tego rodzaju zmiana projektu jest sygnalizowana ostrzeżeniem.
Jest to bardzo przydatna opcja, którą osobiście bym włączył, gdybym używał Eclipse i gdybym programował w Javie.
źródło
Zobacz odpowiedź Samuela na temat zmian zakresu metody. Wydaje mi się, że to jest główny aspekt statycznej metody.
Zapytałeś również o wydajność:
Może wystąpić niewielki wzrost wydajności, ponieważ wywołanie metody statycznej nie wymaga niejawnego odwołania „this” jako parametru.
Jednak ten wpływ na wydajność jest naprawdę niewielki. Dlatego chodzi o zakres.
źródło
Z wytycznych dotyczących wydajności systemu Android:
http://developer.android.com/training/articles/perf-tips.html#PreferStatic
źródło
Cóż, dokumentacja Eclipse mówi o omawianym ostrzeżeniu:
Myślę, że to mówi wszystko. Jeśli metoda jest prywatna i ostateczna i odwołuje się tylko do statycznych elementów członkowskich, dana metoda może być równie dobrze zadeklarowana jako statyczna, a przez to wyraźnie widać, że zamierzamy uzyskiwać z niej dostęp tylko do zawartości statycznej.
Szczerze mówiąc, nie sądzę, aby był za tym jakiś inny tajemniczy powód.
źródło
Brakowało mi kilku liczb dotyczących różnic prędkości. Więc próbowałem je porównać, co okazało się nie takie proste: pętla Java działa wolniej po kilku uruchomieniach / błąd JIT?
W końcu użyłem Calipera i wyniki są takie same, jak podczas ręcznego testowania:
Nie ma mierzalnej różnicy w przypadku połączeń statycznych / dynamicznych. Przynajmniej nie dla Linux / AMD64 / Java7.
Wyniki suwmiarki są tutaj: https://microbenchmarks.appspot.com/runs/1426eac9-36ca-48f0-980f-0106af064e8f#r:scenario.benchmarkSpec.methodName,scenario.vmSpec.options.CMSLargeCoalSurplusPervcentm.scenario.scenario.benchmark. CMSLargeSplitSurplusPercent, scenario.vmSpec.options.CMSSmallCoalSurplusPercent, scenario.vmSpec.options.CMSSmallSplitSurplusPercent, scenario.vmSpec.options.FLSLargestBlockCoalesceProxtimity, scenario1.
a moje własne wyniki to:
Static: 352 ms Dynamic: 353 ms Static: 348 ms Dynamic: 349 ms Static: 349 ms Dynamic: 348 ms Static: 349 ms Dynamic: 344 ms
Klasa testu suwmiarki to:
public class TestPerfomanceOfStaticMethodsCaliper extends Benchmark { public static void main( String [] args ){ CaliperMain.main( TestPerfomanceOfStaticMethodsCaliper.class, args ); } public int timeAddDynamic( long reps ){ int r=0; for( int i = 0; i < reps; i++ ) { r |= addDynamic( 1, i ); } return r; } public int timeAddStatic( long reps ){ int r=0; for( int i = 0; i < reps; i++ ) { r |= addStatic( 1, i ); } return r; } public int addDynamic( int a, int b ){ return a+b; } private static int addStatic( int a, int b ){ return a+b; } }
A moja własna klasa testowa to:
public class TestPerformanceOfStaticVsDynamicCalls { private static final int RUNS = 1_000_000_000; public static void main( String [] args ) throws Exception{ new TestPerformanceOfStaticVsDynamicCalls().run(); } private void run(){ int r=0; long start, end; for( int loop = 0; loop<10; loop++ ){ // Benchmark start = System.currentTimeMillis(); for( int i = 0; i < RUNS; i++ ) { r += addStatic( 1, i ); } end = System.currentTimeMillis(); System.out.println( "Static: " + ( end - start ) + " ms" ); start = System.currentTimeMillis(); for( int i = 0; i < RUNS; i++ ) { r += addDynamic( 1, i ); } end = System.currentTimeMillis(); System.out.println( "Dynamic: " + ( end - start ) + " ms" ); // Do something with r to keep compiler happy System.out.println( r ); } } private int addDynamic( int a, int b ){ return a+b; } private static int addStatic( int a, int b ){ return a+b; } }
źródło
Metody, które można zadeklarować jako statyczne, to te, które nie wymagają tworzenia instancji, na przykład
public class MyClass { public static string InvertText(string text) { return text.Invert(); } }
Które możesz potem w zamian zawołać w dowolnej innej klasie bez inicjowania tej klasy.
public class MyClassTwo { public void DoSomething() { var text = "hello world"; Console.Write(MyClass.InvertText(text)); } }
... Ale to jest coś, co prawdopodobnie już wiesz. Nie daje żadnych rzeczywistych korzyści jako takich, poza wyraźnym wyjaśnieniem, że metoda nie wykorzystuje żadnych zmiennych instancji.
Innymi słowy, najbezpieczniej jest po prostu całkowicie go wyłączyć. Jeśli wiesz, że nigdy nie użyjesz metody w innych klasach (w takim przypadku powinna być po prostu prywatna), wcale nie potrzebujesz, aby była statyczna.
źródło