Une syntaxe étrange pour instancier une classe interne

Je n’imaginais plus que je rencontrerais une syntaxe radicalement nouvelle en Java à ce stade, mais voilà, je viens de rencontrer quelque chose:

Le contexte exact et ce que le code ci-dessous devrait faire est peu pertinent – il est juste là pour donner une sorte de contexte.

J’essaie de créer de manière synthétique un événement dans IT Mill Toolkit, alors j’ai écrit ce genre de ligne:

buttonClick(new Button.ClickEvent(button)); 

Mais, Eclipse me donne le message d’erreur suivant:

Aucune instance englobante de type Button n’est accessible. Doit qualifier l’allocation avec une instance englobante de type Button (egxnew A () où x est une instance de Button).

Quand je réécris la ligne ci-dessus comme suit, elle ne se plaint plus:

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

Donc, ma question est la suivante: que signifie la dernière syntaxe, et pourquoi le premier extrait ne fonctionne-t-il pas? À quoi Java se plaint-il et que fait-il dans la deuxième version?

Informations générales: Button et Button.ClickEvent sont des classes publiques non abstraites.

Les classes Button.ClickEvent (comme Button.ClickEvent ) nécessitent une référence à une instance de la classe externe ( Button ).

Cette syntaxe crée une nouvelle instance de Button.ClickEvent avec sa référence de classe externe définie sur la valeur du button .

Voici un exemple – ignorez l’absence d’encapsulation, etc., uniquement à des fins de démonstration:

 class Outer { Ssortingng name; class Inner { void sayHi() { System.out.println("Outer name = " + name); } } } public class Test { public static void main(Ssortingng[] args) { Outer outer = new Outer(); outer.name = "Fred"; Outer.Inner inner = outer.new Inner(); inner.sayHi(); } } 

Voir la section 8.1.3 de la spécification pour en savoir plus sur les classes internes et les instances englobantes.

Button.ClickEvent est une classe interne non statique, donc une instance de cette classe ne peut exister que dans une instance de Button.

Dans votre deuxième exemple de code, vous avez une instance de Button et vous créez une instance de ClickEvent incluse dans cette occurrence de Button …

Une classe interne non statique en Java contient une référence cachée qui pointe vers une instance de la classe externe dans laquelle elle est déclarée. Le message d’erreur que vous avez reçu vous indique que vous ne pouvez pas créer une nouvelle instance de la classe interne sans spécifier une instance de la classe externe à laquelle elle doit être attachée.

Peut-être que la raison pour laquelle vous n’avez pas vu cette syntaxe est que les classes internes sont souvent allouées dans une méthode de la classe externe, où le compilateur s’en charge automatiquement.

Pour éviter de confondre vous-même et les autres programmeurs avec cette fonctionnalité rarement utilisée, vous pouvez toujours rendre les classes internes statiques.

Si une référence à la classe externe est nécessaire, vous pouvez la transmettre explicitement dans le constructeur.

Vous pouvez en fait le faire , mais vous devez déclarer ClickEvent comme static à static intérieur du Button , et vous ne devriez plus avoir de problème pour utiliser sintax:

 buttonClick(new Button.ClickEvent(button)); 

A la base, la classe ClickEvent appartient directement à la classe Button au lieu d’une instance spécifique (c.-à-d. Un new Button() ) de Button .


À la suite de l’exemple de @Jon Skeet:

 // Button.java class Button { public static class ClickEvent { public ClickEvent(Button b) { System.out.println("Instance: " + this.toSsortingng()); } } } // Test.java public class Test { public static void main(Ssortingng[] args) { Button button = new Button(); buttonClick(new Button.ClickEvent(button)); } public static void buttonClick (Button.ClickEvent ce) { } } 

Votre code comstackrait, avez-vous tapé

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

au lieu de

buttonClick(new Button.ClickEvent(button));

comme un constructeur est une méthode et lorsque vous appelez une méthode en Java, vous devez passer la liste des arguments, même lorsqu’elle est vide.