2009-07-08 10 views
14

Leider habe ich Java seit ungefähr fünf Jahren nicht programmiert und ich kann mich absolut nicht erinnern, wie oder warum der folgende Code funktioniert.Wie lautet dieser Konstruktoraufruf mit folgenden doppelten Klammern?

Ich stolperte über ein ähnliches Beispiel und brach es zu diesem Thema. Der Schwerpunkt liegt auf dem Teil unterhalb des Kommentars: Ich bekomme die Konstruktornotation nicht gefolgt vom Block in doppelten Klammern. Und leider kann ich nichts in der Java-Dokumentation oder mit Google finden (welches Wort sollte ich googlen?).

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

hier sind also meine Fragen:

  1. Wie ist diese Schreibweise/Syntax aufgerufen?
  2. Wo kann ich eine Dokumentation darüber lesen?

Ich hoffe/hoffe, dass ich die zweite Frage selbst beantworten kann, wenn mir jemand die Antwort auf die erste Frage geben kann.

Um es klar zu machen: Ich weiß, der Ausgang ist John Johnson;) Aber ich weiß nicht, warum es funktioniert.

+0

Als ich es zuerst auf Usenet sah ich es für eine Weile zu suchen hatte vor der Realisierung, was los war. Sobald Sie wissen, was es ist, ist es offensichtlich. –

+0

Ich sah diesen netten Trick vor einer Weile auf SO, aber ich sah auch einige Disclaimer, die sagten, dass es einfach war, Sachen damit zu brechen/war nicht sehr zuverlässig. Wenn ich versuchen würde, es zu benutzen, würde ich sicher denken, dass A) ich es jeder Person erklären müsste, um den Code von da an zu sehen, und B) dass ich etwas nachforschen müsste verstehe alle Implikationen der Verwendung dieses Musters. –

+0

Vielen Dank für die schnelle und hilfreiche Antworten! – klekker

Antwort

20

Dies ist bekannt als double brace initialization:

Die erste Strebe schafft eine neue AnonymousInnerClass, der zweite erklärt eine Instanz Initialisierer Block , die ausgeführt wird, wenn die anonyme innere Klasse instanziiert wird. Diese Art von Initialisierungsblocks formal eine „Instanz initializer“ genannt, weil es im Instanzbereich deklariert wird der Klasse - „static initializers“ sind ein verwandtes Konzept, in dem das Schlüsselwort static vor den platziert Klammer, die den Block gestartet wird, und welche sobald auf der Klassenebene ausgeführt wird als die Klassenlader Laden der Klasse der Initialisierer Block kann verwenden, um alle Methoden, Felder und letzten Variablen in die vervollständigt (bei http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6 angegeben) mit Umfang, aber muss man sein Bedenken Sie, dass Initialisierer vor Konstruktoren ausgeführt werden.

Dies funktioniert nur für nicht-finale Klassen, weil es eine anonyme Unterklasse erstellt.

14

Lassen Sie uns das Layout der Code ein wenig anders:

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

Was Sie hier sehen, ist Doppel Klammer Initialisierung genannt. Sie haben eine anonyme innere Unterklasse der Klasse MyTest, zusammen mit einem Initialisiererblock, bei dem es sich um einen Block handelt, der Code enthält, der ausgeführt wird, wenn das Objekt erstellt wird.

Normalerweise würden Sie solchen Code in den Konstruktor einfügen, aber da anonyme innere Klassen keine Konstruktoren haben können, ist dies der einzige Weg zu garantieren, dass der Code ausgeführt wird, wenn er es soll.

Having said that, es ist ein bisschen hässlich, dies zu tun. Es gibt bessere Wege. Allerdings habe ich es verwende ich gelegentlich in der Regel in der folgenden Idiom eine unveränderliche Karte zu erstellen:

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

, die eine neue Karte erstellt, überschreibt es, fügt einige Werte in der Initialisierungsblocks und wickelt es in einer nicht änderbaren Karte.

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

ist die gleiche wie

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

Das sind nicht die gleichen. Ihre Ergebnisse sind nicht die gleiche Klasse. Man erstellt eine Instanz von MyTest. Der andere erstellt eine Instanz einer anonymen Unterklasse von MyTest. Wenn Ihre Methode equals sah wie folgt aus: public boolean equals (Object andere) { if (! Other.class = MyTest.class) {return false; } // einige weitere Kontrollen ... } dann wäre es nicht ihnen die gleiche zu betrachten. –

+3

@mangst Ich denke, du hättest sagen sollen, dass sie "für die meisten Zwecke äquivalent sind"; Sie müssen hier etwas pedantisch sein - die Natur der Ingenieure und aller ... –

Verwandte Themen