2010-06-12 10 views
23

Czy istnieje różnica w skuteczności (na przykład czas wykonania, rozmiar kodu itp.) Między tymi dwoma sposobami działania?Implikacje wydajności anonimowej klasy Javy

Poniżej znajdują się przykłady, które tworzą obiekty i nie robią nic, ale moje rzeczywiste scenariusze mogą tworzyć nowe wątki, nasłuchiści itp. Załóżmy, że następujące fragmenty kodu występują w pętli, co może mieć znaczenie.

Korzystanie anonimowe obiekty:

void doSomething() { 
    for (/* Assume some loop */) { 
     final Object obj1, obj2; // some free variables 

     IWorker anonymousWorker = new IWorker() { 
      doWork() { 
       // do things that refer to obj1 and obj2 
      } 
     }; 
    } 
} 

Definiowanie klasy pierwszej:

void doSomething() { 
    for (/* Assume some loop */) { 
     Object obj1, obj2; 
     IWorker worker = new Worker(obj1, obj2); 
    } 
} 

static class Worker implements IWorker { 
    private Object obj1, obj2; 
    public CustomObject(Object obj1, Object obj2) {/* blah blah */} 

    @Override 
    public void doWork() {} 
}; 
+3

Powinieneś zrobić to, co uważasz za najczystsze i najłatwiejsze do zrozumienia, różnica w wydajności powinna być znacznie mniejsza niż praca wykonywana w doWork(), więc nie będzie to miało znaczenia. Gdybym miał oszacować różnicę, oczekiwałbym około 10 nanosekund. –

+0

Jeśli nie robiłeś kodu krytycznego dla wydajności, a Twój wykład nie zawiera – LegendLength

Odpowiedz

37

Praktyczna różnica między klasami anonimowymi i klasami najwyższego poziomu polega na tym, że klasy anonimowe zawierają niejawne odwołanie do klasy zewnętrznej.

To nie objawi się w działaniu, ale będzie miało wpływ na ciebie, jeśli kiedykolwiek serializujesz te klasy.

+9

Będzie to miało wpływ na wydajność, jeśli nie ma sensu utrzymywanie przy życiu wzmianek o zewnętrznej klasie - szczególnie, gdy śmieciarka się toczy. Będziesz zbierać więcej śmieci na raz, niż pozwolić klasie zewnętrznej wypadać z zakresu w razie potrzeby. Nie jest to duża różnica, ale nie można jej przeoczyć. – dcow

+1

@dcow staram się wyjaśnić, nie złapałem twojego dryfu, kiedy powiedziałeś "... aby odniesienia do zewnętrznej klasy były utrzymywane przy życiu" Czy miałeś na myśli to, że wewnętrzna klasa utrzymuje odniesienia do zewnętrznej klasy? – Cu7l4ss

+3

@ Cu7l4ss - wewnętrzne klasy * do * zawierają odniesienie do zewnętrznej klasy. Zazwyczaj nie jest widoczny, ale jest tam. –

16

Nie powinno być żadnej różnicy jeśli trochę wydajności. Jeśli jest różnica, będzie na poziomie, na którym nie warto się martwić.

IMO, powinieneś skupić się na pisaniu kodu, który jest czytelny i możliwy do utrzymania, i zignoruj ​​problemy z "mikro" wydajnością, dopóki nie uzyskasz jasnych dowodów, że są one istotne ... w oparciu o profilowanie aplikacji.

(Dla rekordu, gdy anonimowa klasa wewnętrzna odnosi się do final w zasięgu obejmującym, jest ona zaimplementowana na poziomie bajtów za pomocą ukrytych argumentów konstruktora i ukrytych atrybutów instancji.Bitekody będą prawie takie same jak kody bajtowe, które można uzyskać z innej implementacji.)

16

Należy pamiętać, że anonimowe klasy są nadal klasami znanymi i w pełni skompilowanymi w czasie kompilacji. Fakt, że definiujesz anonimowe ciało klasowe, być może z wieloma metodami i polami itp. W pętli, nie oznacza, że ​​środowisko wykonawcze musi kompilować tego typu w każdej iteracji.

Tak więc wszelkie różnice w wydajności między tymi dwoma podejściami są pomijalne. Ważnymi czynnikami, które należy rozważyć, są: czytelność, możliwość ponownego użycia, testowalność itd.

1

Spekulacje na temat wydajności kodu to doskonały sposób na zmarnowanie czasu. Nic nie daje porównania z faktycznym testowaniem kodu. Jeśli martwisz się o wydajność, zmień kod . Jeśli podejrzewasz, że kod jest nieoptymalny, zmień profil na kod, aby dowiedzieć się, gdzie znajduje się czas, a następnie spróbuj poprawić te części. W tej chwili może być właściwe, aby rzeczywiście badać kod bajtowy, aby zobaczyć, czy może to dać wskazówkę, która implementacja jest bardziej wydajna.

Po dokonaniu tego, zmierzyć kod ponownie, aby upewnić się, że nie pogorszyło to sytuacji, na przykład przez uczynienie kodu brzydszym i trudniejszym w utrzymaniu.

3

Rzeczywiście, zauważyłem uderzenie wydajności przy tworzeniu instancji wielu instancji anonimowej klasy.

Myśląc, że może to być spowodowane tym, że lokalna klasa jest statyczna, usunąłem to i nie miało to żadnego znaczenia.

W moim przypadku robiłem coś 1000 wybrać 3 razy, co jest 499,500. Wersja z lokalną klasą (niezależnie od statycznego lub nie) zajęła 26 sekund, a wersja z anonimową funkcjonalnie identyczną klasą zajęła 2 minuty 20 sekund.

+0

Jest wiele rzeczy do rozważenia, ponieważ zagnieżdżone klasy mogą powodować dodatkowe efekty uboczne, jeśli są intensywnie używane. Na przykład każda próba uzyskania dostępu do prywatnych elementów lub metod innego obiektu (takiego jak zewnętrzny) zostanie zakończona generowaną publicznie metodą (prosty getter) i wykorzystaną w zamian. Jest to coś, o czym powinieneś pamiętać podczas zagnieżdżania logiki. Nie ma linku do tego, ale odnaleziono go jakiś czas temu w specyfikacji JVM. – Pijusn

+0

Pomocne może być podanie kodu testu porównawczego. –

3

Jeśli chodzi o wyniki, należy rozważyć, czy klasa wewnętrzna powinna zostać stworzona, czy nie.

Przykładem złej praktyki jest coś takiego:

public List<String> someMethod() { 
     return new ArrayList<String>() {{ 
         add("Item one"); 
         add("Item two"); 
       }}; 
} 

Chociaż składniowej wygoda wygląda mądry na pierwszy rzut oka, to (często niezauważone) tworzy anonimowej klasy wewnętrznej, której celem utrzymuje odniesienie do zewnętrznej instancji . Ponieważ ten obiekt jest również przekazywany na zewnątrz jako wartość wyniku jakiegoś Metodą, nie możesz być pewien, co robi rozmówca z tą listą. Jeśli wstawi wynikową instancję klasy ArrayList do pewnej statycznej zmiennej, twój bieżący obiekt również będzie przechowywany na zawsze!

+0

Następnie, w jaki sposób zwrócić listę? jaka jest twoja propozycja lepszej praktyki? Dzięki – jlanza

+0

Pytanie o komentarz za trzy lata? Ok, no, ponieważ Java 7, która będzie zwracać Arrays.asList ("Pozycja pierwsza", "Pozycja druga"); Czy nie tak? – Det

Powiązane problemy