2009-07-08 12 views
14

Niestety, nie koduję Javy od około pięciu lat i absolutnie nie pamiętam, jak i dlaczego działa poniższy kod.Co to jest połączenie konstruktora z następującymi podwójnymi nawiasami klamrowymi?

Natknąłem się na podobny przykład i połamałem go. Nacisk położony jest na część pod komentarzem: Nie otrzymuję notacji konstruktora, a następnie bloku w podwójnych nawiasach. I niestety nie mogę znaleźć niczego w dokumentacji Java lub używając Google (jakie słowo (-y) powinienem (-am) google?).

package syntaxtest; 

public class Main { 

    public static void main(String[] args) { 

     // What kind of notation is this? 
     MyTest tester = new MyTest() {{ 
      setName("John Johnson"); 
     }}; 

     System.out.println(tester.getName()); 
    } 
} 


class MyTest { 
    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

Więc oto moje pytania:

  1. Jak to notacja/składnia nazywa?
  2. Gdzie mogę przeczytać o tym dokumentację?

Zgaduję/mam nadzieję, że będę w stanie odpowiedzieć na drugie pytanie sam, jeśli ktoś może udzielić mi odpowiedzi na pierwsze pytanie.

Aby było jasne: wiem, że wyjście to John Johnson;) Ale nie wiem, dlaczego działa.

+0

Kiedy pierwszy raz zobaczyłem go na Usenecie musiałem spojrzeć na nią przez chwilę zanim zorientował, co się dzieje. Kiedy już wiesz, co to jest, jest to oczywiste. –

+0

Widziałem tę schludną sztuczkę jakiś czas temu na SO, ale widziałem też sporo zastrzeżeń, mówiących, że łatwo było z nim zerwać/nie było bardzo niezawodne. Gdybym spróbował go użyć, z pewnością uważałbym, że A) musiałbym wytłumaczyć to każdej osobie, aby zobaczył kod od tego momentu, i B) Że będę musiał przeprowadzić pewne badania zrozumieć wszystkie konsekwencje używania tego wzoru. –

+0

Dziękuję wszystkim za szybkie i pomocne odpowiedzi! – klekker

Odpowiedz

20

ten jest znany jako double brace initialization:

Pierwsza klamra tworzy nowy AnonymousInnerClass, drugi deklaruje blok inicjujący instancja , który jest uruchamiany, gdy anonimowy wewnętrzna klasa jest tworzony. Ten typ bloku inicjatora jest formalnie nazywany „Wystąpienie inicjator”, ponieważ jest zadeklarowana w ramach instancji klasy - „inicjalizatory statyczne” są związane pojęcie gdzie statyczny parametr jest umieszczony przed klamra, który rozpoczyna blok, a które jest wykonywany na poziomie klasy jak najszybciej jak classloader zakończeniu ładowania klasę (określone w http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6) blok inicjator może używać żadnych metod, pól i zmiennych końcowych dostępny w zawierający zakres, ale musi być: nieufnie wobec faktu, że inicjatory są uruchamiane przed konstruktorami .

Działa to tylko dla niefinałowych klas , ponieważ tworzy anonimową podklasę . Układ

14

Miejmy kod nieco inaczej:

MyTest tester = new MyTest() { 
    { 
    setName("John Johnson"); 
    } 
}; 

Co można zobaczyć tutaj nazywa podwójna klamra inicjalizacji. Masz anonimową podklasę wewnętrzną klasy MyTest wraz z blokiem inicjalizacyjnym, który jest blokiem zawierającym kod uruchamiany podczas konstruowania obiektu.

Zwykle taki kod zostałby wstawiony do konstruktora, ale ponieważ anonimowe klasy wewnętrzne nie mogą mieć konstruktorów, jest to jedyny sposób na zagwarantowanie, że kod zostanie uruchomiony, gdy powinien.

Powiedziawszy to, jest to trochę brzydkie. Są lepsze sposoby. Jednakże, należy używać go sobie od czasu do czasu, zwykle w następującym idiomu stworzyć niezmienny mapę:

final Map<String, Integer> textToInt = Collections.unmodifiableMap(new HashMap<String, Integer>() {{ 
    put("one", 1); 
    put("two", 2); 
    // etc 
}}); 

który tworzy nową mapę, zastępuje go, dodaje pewne wartości do niego w bloku inicjatora i zawija je w niezmodyfikowanej mapie.

-5
MyTest tester = new MyTest() {{ 
    setName("John Johnson"); 
}}; 

jest taka sama jak

MyTest tester = new MyTest(); 
tester.setName("John Johnson"); 
+3

To nie to samo. Ich wyniki nie są tej samej klasy. Jeden tworzy instancję MyTest. Drugi tworzy instancję anonimowej podklasy MyTest. Jeśli metoda equals wyglądał następująco: publicznych równych Boolean (inny obiekt) { if (! Other.class = MyTest.class) {return false; } // kilka kontrole ... } wtedy byłoby nie do rozważenia im takie same. –

+3

@mangst myślę, że należy powiedzieć, że są „Funkcjonalność equivilent dla większości celów”; trzeba być trochę pedantyczny tutaj - charakter inżynierów i wszystko ... –

Powiązane problemy