2009-07-08 10 views
14

Purtroppo non ho codificato Java per circa cinque anni e non riesco assolutamente a ricordare come o perché il codice seguente funzioni.Cos'è questa chiamata al costruttore con le seguenti doppie parentesi?

Mi sono imbattuto in un esempio simile e l'ho interrotto. L'enfasi è nella parte sotto il commento: non ottengo la notazione del costruttore seguita dal blocco tra parentesi quadre. E sfortunatamente non riesco a trovare nulla nella documentazione Java o usando Google (quale parola devo usare su 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; 
    } 
} 

Così qui sono le mie domande:

  1. Come è questa notazione/sintassi chiamato?
  2. Dove posso leggere qualche documentazione a riguardo?

Immagino/spero di poter rispondere alla seconda domanda da solo se qualcuno mi può fornire la risposta alla prima domanda.

Per chiarire: so che l'output è John Johnson;) Ma non so perché funzioni.

+0

Quando ho visto la prima volta su Usenet ho dovuto guardare per un po 'prima di capire cosa stava succedendo. Una volta che sai cos'è, è ovvio. –

+0

Ho visto questo semplice trucco qualche tempo fa su SO, ma ho visto anche alcuni disclaimer che dicevano che era facile rompere cose con esso/non era molto affidabile. Se avessi intenzione di provare ad usarlo, sarei sicuro di considerare che A) Dovrei spiegarlo ad ogni persona per vedere il codice da quel momento in poi, e B) Che dovrei fare qualche ricerca per capire tutte le implicazioni dell'uso di questo modello. –

+0

Grazie a tutti per le risposte rapide e utili! – klekker

risposta

20

questo è noto come double brace initialization:

La prima doppietta crea un nuovo AnonymousInnerClass, la seconda dichiara un blocco di inizializzazione esempio che viene eseguito quando l'anonimo interno classe viene creata un'istanza. Questo tipo di blocco di inizializzazione è formalmente chiamato una "istanza di inizializzazione", perché è dichiarata all'interno dell'istanza ambito della classe - "inizializzatori statici" sono un concetto relativo in cui la parola chiave è statica posizionata prima del tutore che avvia il blocco, e che viene eseguito a livello di classe appena il classloader completa caricamento classe (fissata al http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6) il blocco di inizializzazione può utilizzare qualsiasi metodi, campi e variabili finali disponibile in contenente l'ambito, ma deve essere diffidare del fatto che gli inizializzatori vengono eseguiti prima dei costruttori .

Questo funziona solo per classi non definitive perché crea una sottoclasse anonima anonima. Layout

14

di lasciare che il codice di un po 'diverso:

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

Quello che vedete qui è chiamato doppia doppietta di inizializzazione. Si dispone di una sottoclasse interna anonima della classe MyTest, insieme a un blocco di inizializzazione, che è un blocco che contiene codice eseguito quando viene costruito l'oggetto.

Normalmente, si inserisce tale codice nel costruttore, ma poiché le classi interne anonime non possono avere costruttori, questo è l'unico modo per garantire che il codice venga eseguito quando è previsto.

Detto questo, è un po 'brutto farlo. Ci sono modi migliori. Tuttavia, io uso io stesso a volte, di solito nella seguente forma per creare una mappa immutabile:

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

che crea una nuova mappa, prevale su di esso, aggiunge alcuni valori ad esso nel blocco di inizializzazione, e avvolge in una mappa non modificabile.

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

è lo stesso di

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

Questi non sono gli stessi. I loro risultati non sono della stessa classe. Uno crea un'istanza di MyTest. L'altro crea un'istanza di una sottoclasse anonima di MyTest. Se il tuo metodo di uguale è il seguente: uguale al booleano pubblico (altro oggetto) { if (other.class! = MyTest.class) {return false; } // alcuni altri controlli ... } quindi non li considererebbe lo stesso. –

+3

@mangst Penso che dovresti aver detto che sono "Funzionalità equivoche per la maggior parte degli scopi"; devi essere un po 'pedante qui - la natura degli ingegneri e di tutti ... –