2009-03-11 14 views
41

no me imaginaba que iba a encontrarse radicalmente nueva sintaxis en Java más en esta etapa, pero lo he aquí, yo sólo encontré algo:sintaxis extraño para crear instancias de una clase interna

El contexto exacto y lo que el El siguiente código debe hacer es bastante irrelevante: está ahí solo para dar algún tipo de contexto.

Estoy intentando crear sintéticamente un evento en TI Molino Toolkit, así que escribí este tipo de línea:

buttonClick(new Button.ClickEvent(button)); 

Pero, Eclipse me da el siguiente mensaje de error:

No se puede acceder a ninguna instancia adjunta de tipo Button. Debe calificar la asignación con una instancia adjunta de tipo Botón (por ejemplo, x.new A() donde x es una instancia de Button).

Cuando vuelvo a escribir la línea anterior de la siguiente manera, no se queja más:

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

lo tanto, mi pregunta es: ¿Qué significa este último sintaxis, exactamente, y por qué no lo hace el primer fragmento de trabajo? ¿De qué se queja Java, y qué está haciendo en la segunda versión?

Información de fondo: Button y Button.ClickEvent son clases públicas no abstractas.

+0

Interesante pregunta, pero el título podría quizás ser más sofisticados. – mafu

+0

Puede sugerir uno. No sabía cómo llamar a la sintaxis en ese momento, por lo que el título permaneció, desafortunadamente, como extraño. –

Respuesta

69

Las clases internas (como Button.ClickEvent) necesitan una referencia a una instancia de la clase externa (Button).

Esa sintaxis crea una nueva instancia de Button.ClickEvent con su referencia de clase externa establecida en el valor de button.

He aquí un ejemplo - ignorar la falta de encapsulación, etc., es sólo a efectos de demostración:

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

Ver section 8.1.3 of the spec para más información sobre las clases internas y los casos que encierran.

+7

Si la clase interna no necesita la referencia a la clase externa para funcionar, puede eliminar este requisito utilizando la palabra clave estática en la declaración de clase interna - clase estática interna en el ejemplo anterior - aunque obviamente no tendría acceso a la propiedad Outer.name ...! –

+0

@Jon ¿hay algún nombre técnico específico para este modismo de crear una instancia de clase interna no estática? – Inquisitive

+0

@Inquisitive: es solo una instancia de una clase interna. –

9

Button.ClickEvent es una clase interna no estática por lo que una instancia de esta clase solo puede existir encerrada en una instancia de Button.

En el segundo ejemplo de código que tiene una instancia de Button y se crea una instancia de ClickEvent cerrado en este caso ... Botón

8

Una clase interna no estática en Java contiene una referencia oculta que apunta a una instancia de la clase externa en la que está declarada. Así que el mensaje de error que recibió originalmente le dice que no puede crear una nueva instancia del interior clase sin especificar también una instancia de la clase externa para que se adjunte.

Quizás la razón por la que no ha visto esa sintaxis antes es porque las clases internas a menudo se asignan en un método de la clase externa, donde el compilador se encarga de esto automáticamente.

3

Para no confundirse ni a los demás programadores con esta función poco utilizada, siempre puede hacer que las clases internas estén estáticas.

En caso de que se necesite una referencia a la clase externa, puede pasarla explícitamente en el constructor.

+0

O hacer que las clases internas sean privadas, y apegarse a esto implícitamente. –

-1

Su código compile, tenías que ha escrito

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

en lugar de

buttonClick(new Button.ClickEvent(button));

como constructor es un método y cuando se llama a un método en Java debe pasar la lista de argumentos, incluso cuando está vacío.

+0

En realidad, no, eso no funciona, porque intenta llamar al método ClickEvent (Botón) con eso, que no encuentra ... –

+0

nuevo Botón(). ¿Nuevo ClickEvent (botón)? –

1

En realidad puede hacer que, pero usted tiene que declarar ClickEvent como static dentro Button, y entonces no debería tener ningún problema con que SINTAX:

buttonClick(new Button.ClickEvent(button)); 

Básicamente static hace que la clase ClickEvent pertenecen directamente a la clase Button en lugar de una instancia específica (es decir, new Button()) de Button.


Siguiendo el ejemplo @ 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) { 
    } 
} 
Cuestiones relacionadas