Sintassi sconosciuta per creare un'istanza di una classe interna
-
10-07-2019 - |
Domanda
Non immaginavo che avrei incontrato una sintassi radicalmente nuova in Java in questa fase, ma ecco, ho appena incontrato qualcosa:
Il contesto esatto e ciò che il codice seguente dovrebbe fare è abbastanza irrilevante: è lì solo per dare un qualche tipo di contesto.
Sto cercando di creare sinteticamente un evento in IT Mill Toolkit, quindi ho scritto questo tipo di linea:
buttonClick(new Button.ClickEvent(button));
Ma Eclipse mi dà il seguente messaggio di errore:
Non è accessibile alcuna istanza chiusa di tipo Button. Deve qualificare l'allocazione con un'istanza chiusa di tipo Button (ad esempio x.new A () dove x è un'istanza di Button).
Quando riscrivo la riga sopra come segue, non mi lamento più:
buttonClick(button.new ClickEvent(button)); // button instanceof Button
Quindi, la mia domanda è: Cosa significa esattamente quest'ultima sintassi e perché il primo frammento non funziona? Di cosa si lamenta Java e cosa sta facendo nella seconda versione?
Informazioni sullo sfondo: sia Button
che Button.ClickEvent
sono classi pubbliche non astratte.
Soluzione
Le classi interne (come Button.ClickEvent
) necessitano di un riferimento a un'istanza della classe esterna ( Button
).
Tale sintassi crea una nuova istanza di Button.ClickEvent
con il riferimento di classe esterno impostato sul valore di button
.
Ecco un esempio: ignora la mancanza di incapsulamento, ecc., è solo a scopo dimostrativo:
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 sezione 8.1.3 delle specifiche per ulteriori informazioni sulle classi interne e le istanze di chiusura.
Altri suggerimenti
Button.ClickEvent è una classe interna non statica, quindi un'istanza di questa classe può esistere solo racchiusa in un'istanza di Button.
Nel tuo secondo esempio di codice hai un'istanza di Button e crei un'istanza di ClickEvent racchiusa in questa istanza di Button ...
Una classe interna non statica in Java contiene un riferimento nascosto che punta a un'istanza della classe esterna in cui è dichiarata. Quindi il messaggio di errore che hai originariamente ti dice che non puoi creare una nuova istanza della classe interna senza specificare anche un'istanza della classe esterna a cui collegarla.
Forse la ragione per cui non hai mai visto quella sintassi prima è che le classi interne sono spesso allocate in un metodo della classe esterna, in cui il compilatore si occupa automaticamente di questo.
Per evitare di confondere te stesso e gli altri programmatori con questa funzione usata raramente puoi sempre rendere statiche le classi interne.
Nel caso in cui sia necessario un riferimento alla classe esterna, puoi passarla esplicitamente nel costruttore.
In realtà puoi farlo , ma devi dichiarare ClickEvent
come static
all'interno del pulsante
, e quindi non dovresti avere problemi ad usare la tua sintassi:
buttonClick(new Button.ClickEvent(button));
Fondamentalmente statico
fa in modo che la classe ClickEvent
appartenga direttamente alla classe Button
anziché a un'istanza specifica (ad esempio new Button ()
) del pulsante
.
Seguendo l'esempio di @Jon Skeet:
// 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) {
}
}
Il tuo codice verrebbe compilato, se avessi digitato
buttonClick(new Button().ClickEvent(button));
anziché
buttonClick (nuovo Button.ClickEvent (pulsante));
come costruttore è un metodo e quando si chiama un metodo in Java è necessario passare l'elenco degli argomenti, anche quando è vuoto.