2009-03-11 20 views
41

non immaginavo che avrei incontrato radicalmente nuova sintassi di Java più in questa fase, ma ecco e vede qualcosa, ho appena incontrato:sintassi Strano per istanziare una classe interna

Il contesto esatto e ciò che il il codice sotto dovrebbe essere irrilevante - è lì solo per dare un qualche tipo di contesto.

Sto cercando di creare sinteticamente un evento nel settore IT Mill Toolkit, così ho scritto questo tipo di linea:

buttonClick(new Button.ClickEvent(button)); 

Ma, Eclipse mi dà il seguente messaggio di errore:

Nessuna istanza allegata di tipo Pulsante è accessibile. È necessario qualificare l'allocazione con un'istanza di tipo Button allegata (ad es. X.new A() dove x è un'istanza di Button).

Quando riscrivo la linea precedente come segue, ma non si lamenta più:

buttonClick(button.new ClickEvent(button)); // button instanceof Button 

Quindi, la mia domanda è: Che cosa significa quest'ultimo sintassi, esattamente, e perché non lo fa il primo frammento di lavoro? Cosa si lamenta di Java e cosa sta facendo nella seconda versione?

Informazioni di base: Button e Button.ClickEvent sono classi pubbliche non astratte.

+0

Domanda interessante, ma il titolo potrebbe forse essere più sofisticati. – mafu

+0

Sei libero di suggerirne uno. Non sapevo cosa chiamare la sintassi al momento, quindi il titolo è rimasto, purtroppo, come strano. –

risposta

69

classi interne (come Button.ClickEvent) hanno bisogno di un riferimento a un'istanza della classe esterna (Button).

Questa sintassi crea una nuova istanza di Button.ClickEvent con il suo riferimento di classe esterno impostato sul valore di button.

Ecco un esempio - ignorano la mancanza di incapsulamento, ecc, è solo ai fini della dimostrazione:

class Outer 
{ 
    String name; 

    class Inner 
    { 
     void sayHi() 
     { 
      System.out.println("Outer name = " + name); 
     } 
    } 
} 

public class Test 
{ 
    public static void main(String[] args) 
    { 
     Outer outer = new Outer(); 
     outer.name = "Fred"; 

     Outer.Inner inner = outer.new Inner(); 
     inner.sayHi(); 
    } 
} 

Vedi section 8.1.3 of the spec info sui classi interne e le istanze che racchiudono.

+7

Se la classe interna non ha bisogno del riferimento alla classe esterna per funzionare, è possibile eliminare questo requisito utilizzando la parola chiave static nella dichiarazione della classe interna - la classe statica Inner nell'esempio precedente - sebbene ovviamente non si avrebbe accesso alla proprietà Outer.name ...! –

+0

@Jon esiste un nome tecnico specifico per questo idioma di creazione di un'istanza di classe interna non statica? – Inquisitive

+0

@Inquisitive: è solo un'istanza di una classe interiore. –

9

Button.ClickEvent è una classe interna non statica in modo che un'istanza di questa classe possa esistere solo racchiusa in un'istanza di Button.

Nel tuo esempio secondo codice si dispone di un'istanza di Button e si crea un'istanza di ClickEvent racchiuso in questo caso Button ...

8

Una classe interna non statica in Java contiene un riferimento nascosto che punta a un'istanza della classe esterna in cui è stato dichiarato. Quindi il messaggio di errore che hai ricevuto in origine ti sta dicendo che non puoi creare una nuova istanza della parte interna classe senza specificare anche un'istanza della classe esterna per la quale deve essere collegata.

Forse la ragione per cui non si è mai vista questa sintassi è che le classi interne sono spesso allocate in un metodo della classe esterna, dove il compilatore si occupa automaticamente di questo.

3

Per evitare di confondere te stesso e altri programmatori con questa funzione raramente utilizzata puoi sempre rendere statiche le classi interne.

Nel caso in cui sia necessario un riferimento alla classe esterna, è possibile passarlo esplicitamente nel costruttore.

+0

Oppure rendere private le classi interne e attenersi a ciò che è implicito. –

-1

Il codice dovrebbe compilare, aveva digitato

buttonClick(new Button().ClickEvent(button)); 

invece di

buttonClick(new Button.ClickEvent(button));

come un costruttore è un metodo e quando si chiama un metodo in Java è necessario passare l'elenco dei argomenti, anche quando è vuoto.

+0

In realtà, no, non funziona, perché prova a chiamare il metodo ClickEvent (Button) con quello, che non trova ... –

+0

new Button(). New ClickEvent (pulsante)? –

1

Si può effettivamente farlo, ma si deve dichiarare ClickEvent come static all'interno Button, e poi non si dovrebbe avere alcun problema con voi sintassi:

buttonClick(new Button.ClickEvent(button)); 

Fondamentalmente static rende la classe ClickEvent appartiene direttamente alla classe Button anziché a un'istanza specifica (ad esempio new Button()) di Button.


Seguendo @ Jon Skeet esempio:

// Button.java 
class Button 
{ 

    public static class ClickEvent 
    { 
     public ClickEvent(Button b) 
     { 
      System.out.println("Instance: " + this.toString()); 
     } 
    } 
} 

// Test.java 
public class Test 
{ 
    public static void main(String[] args) 
    { 
     Button button = new Button(); 
     buttonClick(new Button.ClickEvent(button)); 
    } 

    public static void buttonClick (Button.ClickEvent ce) { 
    } 
}