Classes internes en java

Classe interne signifiant
Comme son nom l’indique, une classe dans une autre classe est appelée Classe interne.
Les classes internes partagent une relation spéciale avec sa classe contenant en ce sens qu’elle a accès à tous les membres de la classe externe (même les private).
En effet, une classe interne est également membre de la classe externe, tout comme les autres champs et méthodes.
Puisqu’une classe interne est une classe à l’intérieur d’une autre classe, elle peut également être appelée classe imbriquée.
Types de classes internes
Une classe interne peut être des types suivants.

  1. Classe interne normale ou régulière ou imbriquée (normalement appelée juste classe interne)
  2. Classe interne locale de la méthode.
  3. Classe interne anonyme.
  4. Classe imbriquée statique

1. Classe interne imbriquée
Cette section va creuser dans tous les détails d’une classe interne. Pour plus de simplicité, considérez les classes suivantes

class Outer { private String outerField = "Outer"; class Inner { private String innerField = "Inner"; }}

Ici Outer est la classe externe et Inner est la classe interne qui est contenue dans Outer.

Création d’un objet de classe interne
Une classe interne est dans une autre classe. La classe contenant est appelée classe externe. Ainsi, une classe interne ne peut exister sans classe externe et il en va de même pour son objet (ou instance).
Un objet de classe interne ne peut exister sans un objet de classe externe.
Cela signifie que pour créer une instance de classe interne, vous devez avoir une instance de classe externe.
Ainsi, l’objet de la classe interne peut être créé par la méthode donnée ci-dessous.

// first, create object of outer classOuter outerObject = new Outer();// create object of inner classInner innerObject = outerObject.new Inner();

Comme il ressort clairement de l’exemple, pour créer un objet de classe interne, un objet de classe externe est nécessaire.
Il existe également une méthode à main courte pour créer un objet de classe interne.

Inner innerObject = new Outer().new Inner();

Cette méthode nécessite également un objet de classe externe.
Juste Remember….An l’objet de la classe interne ne peut pas être créé sans un objet de sa classe contenant (ou externe).

Création d’un objet de classe interne Dans une classe externe
L’exemple précédent suppose que vous instanciez une classe interne à partir de quelque part en dehors de la classe externe.
Mais, dans la plupart des cas, un objet de classe interne est requis à l’intérieur de la classe externe uniquement, car la classe externe utilise la classe interne.
Alors, comment créer un objet de classe interne à partir de la classe externe?
Considérez la classe d’échantillon modifiée ci-dessous.

class Outer { private String outerField = "Outer"; public void createInnerClassObject() { // create an object of inner class Inner innerObject = new Inner(); } class Inner { private String innerField = "Outer"; }}

Remarquez la ligne Inner innerObject = new Inner();.
Auparavant, il était indiqué qu’un objet de classe interne ne pouvait pas être créé sans un objet de classe externe, mais l’extrait de code ci-dessus le fait. Confus!!!!
La syntaxe ci-dessus est valide car elle est écrite dans une méthode de classe externe.
Lorsque ce code est en cours d’exécution, une instance de classe externe est déjà présente, qui exécute la méthode.

Rappelez-vous toujours que Pour créer (ou accéder) à un objet de classe interne, il doit y avoir une instance de classe externe.

Pour résumer,

  1. Lorsqu’un objet de classe interne est créé à partir de la classe externe, il peut être créé directement en tant que Inner innerObject = new Inner();.
  2. Lorsqu’un objet de classe interne est créé à partir de l’extérieur de la classe externe, il doit être créé en tant que Inner innerObject = new Outer().new Inner();.

Lorsque des objets de classe externe et interne sont imprimés, voici la sortie générée:

Instance de classe externe : Instance de classe interne externe @659e0bfd
: Outer@Inner @2a139a55

Référence à une instance, à des champs et à des méthodes de classe externe de la classe interne
Une classe interne est également membre de sa classe contenant, comme les autres champs et méthodes.
Ainsi, il peut accéder à d’autres champs et méthodes de classe externe de la même manière que d’autres champs et méthodes s’accèdent les uns aux autres, directement.
Cela est vrai lors de l’accès aux champs et méthodes de classe externe à partir de la classe interne.

Mais, lors de la référence à l’instance de la classe externe, il y a une différence. Afin de référencer l’instance actuelle d’une classe, le mot clé this est utilisé.
Dans le cas d’une classe interne, l’utilisation de this dans la classe interne fait référence à l’instance actuelle de la classe interne et non à sa classe externe.
Pour référencer l’instance de la classe externe à partir de la classe interne, nous devons ajouter le nom de la classe au mot clé this.

Ainsi, pour référencer l’instance de classe externe à partir de la classe interne, utilisez la syntaxe Outer.this.
Reportez-vous à l’exemple ci-dessous pour la compréhension.

class Outer { private String outerField = "Outer"; public void createInnerClassObject() { // create an object of inner class Inner innerObject = new Inner(); } class Inner { private String innerField = "Outer"; public innerClassMethod() { // access outer class field System.out.println("Outer field : " + outerField); // access inner class instance System.out.println("Inner instance : " + this); // access outer class instance System.out.println("Outer instance : " + Outer.this); } }}

Sortie

Champ externe: Externe
Instance interne:
Instance externe :

2. Classe Interne Locale de méthode
Comme son nom l’indique, une classe définie dans une méthode est une Classe interne locale de méthode.
Oui, c’est possible.
Vous pouvez définir une classe dans une méthode comme indiqué ci-dessous.

// outer classclass Outer { // outer class method public void createClass() { // class inside a method class Inner { // inner class method public void innerMethod() { System.out.println("Method local inner class"); } } // inner class ends } // method ends}

Le code ci-dessus a une classe externe contenant une méthode.
Cette méthode définit une classe qui se trouve à l’intérieur du corps de la méthode, donc appelée classe interne locale de la méthode.
Notez que la classe interne a également sa propre définition de méthode.

Instancier une classe interne locale de méthode
Le code précédent déclare une classe interne locale de méthode mais il ne crée aucun objet de classe interne.
Maintenant, la question se pose, comment créer un objet de classe interne locale de méthode.
Puisqu’une classe interne locale de méthode est définie à l’intérieur d’une méthode, elle n’est visible qu’à l’intérieur de cette méthode et son objet peut également être créé uniquement à l’intérieur de cette méthode.
Le code ci-dessous crée un objet de la classe interne locale de la méthode et appelle sa méthode.

// outer classpublic class Outer { // outer class method public void createClass() { // class inside a method class Inner { // inner class method public void innerMethod() { System.out.println("Method local inner class method called"); } } // inner class ends // create inner class object Inner innerObject = new Inner(); // call inner class method innerObject.innerMethod(); } // outer class method ends // Main method public static void main(String args) { // create object of outer class Outer outerObject = new Outer(); // call outer class method outerObject.createClass(); }}

Lorsque le code ci-dessus est exécuté, voici la sortie

Méthode méthode de classe interne locale appelée

Cela montre que lorsque la méthode de classe externe est appelée, elle crée un objet de classe interne et appelle la méthode de classe interne.

Classe interne locale de la méthode: Les points à retenir l’instruction
qui crée un objet de la classe interne locale de la méthode doivent être écrits en dehors du corps de la classe.
Ainsi, la ligne Inner innerObject = new Inner(); devrait venir après la fin de la classe locale.

  1. Une classe interne locale de méthode ne peut être instanciée qu’à l’intérieur de la méthode dans laquelle elle est déclarée.
    Cela a du sens car une classe de méthode est visible à l’intérieur de la méthode uniquement, donc son objet peut être créé à l’intérieur de cette méthode uniquement.
  2. Une classe interne locale de méthode ne peut pas accéder aux variables locales de la méthode dans laquelle elle est déclarée.
    S’il doit y accéder, ils doivent être marqués final.
    Ceci est applicable avant java 8.
  3. Vous ne pouvez pas accéder à une variable locale de méthode dans une classe interne locale de méthode, puis la réaffecter. Ce sera une erreur de compilation.
    Ceci est applicable à partir de java 8 car les versions antérieures à java 8 ne vous permettront même pas d’accéder à une variable locale de méthode à l’intérieur de la classe interne.
  4. Une classe interne locale de méthode peut accéder aux champs et autres méthodes de la classe à laquelle appartient la méthode contenant la classe interne.
  5. Une classe interne locale de méthode peut accéder aux champs static et aux autres méthodes static de la classe à laquelle appartient la méthode contenant la classe interne uniquement lorsque la méthode contenant est static.

3. Classes internes anonymes
Anonyme signifie dont le nom n’est pas connu. Dans le contexte de java, une classe anonyme est une classe qui n’a pas de nom.
Le terme Classe anonyme ne s’applique qu’aux classes internes, car les classes externes doivent avoir un nom.
Une classe anonyme est une classe interne car elle sera toujours définie dans une autre classe.

Types de classe anonyme en java
En réalité, une classe anonyme est une implémentation d’une classe déjà existante ou d’une interface qui est écrite ailleurs mais elle est à nouveau définie dans une autre classe selon les besoins.
Cela peut sembler déroutant, mais les exemples qui suivent clarifieront le concept.

Selon que la classe anonyme est une implémentation d’une classe ou d’une interface, elle peut appartenir aux deux catégories suivantes

A. Sous-classe d’une classe
Commençons d’abord par un exemple

// Already existing classclass Website {public void printName() {System.out.println("No website till now");}}class SearchEngine { // Notice the syntax Website w = new WebSite() { public void printName() { System.out.println("Website is codippa.com"); } };}

Dans l’exemple ci-dessus, il existe une classe nommée Website qui est déjà créée.
Une autre classe SearchEngine redéfinit cette classe, implémente sa méthode et l’affecte à une variable de référence du même type que la classe réelle.
Il est également possible d’appeler la méthode nouvellement implémentée en utilisant cette variable de référence.

Rappelez-vous que la classe anonyme nouvellement implémentée est une sous-classe de la classe réelle.
Il suit le polymorphisme et son objet peut être transmis partout où l’objet de la classe de site Web est attendu.
Passez par l’exemple ci-dessous pour l’illustration.

class Website { public void printName() { System.out.println("No website till now"); }}class SearchEngine { // Notice the syntax Website w = new WebSite() { public void printName() { System.out.println("Website is codippa.com"); } }; // Expects an instance of Website class public void getWebsite(Website web) { // call the method of Website class web.printName(); } // Main method public static void main(String args) { // create an object of this class SearchEngine obj = new SearchEngine(); // call its method and pass instance of Website class obj.getWebsite(obj.w); }}

Au lieu de prédéfinir l’implémentation de la classe Website, elle peut être définie si nécessaire, c’est-à-dire lors de l’appel de la méthode getWebsite.
Ainsi la méthode principale peut être modifiée en tant que

public static void main(String args) { SearchEngine obj = new SearchEngine(); // Notice the implementation of Website class as argument obj.getWebsite(new Website() { public void print() { System.out.println("Dynamic implementation"); } });}

L’implémentation ci-dessus n’est affectée à aucune variable de référence, elle n’a pas de nom et donc le nom Anonyme.

Il n’est pas nécessaire que les deux classes soient dans le même fichier ou package. Ils peuvent être situés n’importe où l’un par rapport à l’autre.

B.Implémenteur d’interface
Une classe anonyme peut également être définie comme l’implémenteur d’une interface.
Dans ce cas, il définira l’implémentation des méthodes déclarées dans l’interface et pourra être passé n’importe où l’objet de l’interface est attendu.
Reportez-vous à l’exemple ci-dessous pour le préciser.

interface WebInterface { // interface method declaration public void print();}class SearchEngine { // Notice the syntax WebInterface w = new WebInterface() { // Interface method implementation public void printName() { System.out.println("Website is codippa.com"); } }; // Expects an instance of WebInterface interface public void getWebsite(WebInterface web) { // call the method of WebInterface web.printName(); } // Main method public static void main(String args) { // create an object of this class SearchEngine obj = new SearchEngine(); // call its method and pass instance of WebInterface obj.getWebsite(obj.w); }}

Comme précédemment, l’implémentation de l’interface en tant que classe anonyme peut être créée si nécessaire, comme indiqué ci-dessous.

public static void main(String args) { SearchEngine obj = new SearchEngine(); // Notice the implementation of WebInterface as argument obj.getWebsite(new WebInterface() { public void print() { System.out.println("Dynamic implementation"); } });}
Notez l’utilisation du mot clé new avant le nom de l’interface. La classe anonyme est le seul endroit où c’est possible.

Polymorphisme dans les classes anonymes
Comme indiqué précédemment, les classes anonymes suivent le polymorphisme.
Comme ce sont des sous-classes, elles devraient suivre le polymorphisme. Cette section détaillera comment.
Considérez la classe ci-dessous.

class Metal { public void printThickness() { System.out.println("Thick enough"); }}class MetalDriver { // Anonymous class definition Metal metal = new Metal() { public void printThickness() { System.out.println("Thick enough"); } // new method public boolean hasLustre() { return false; } }; public void printMetalDetail(Metal m) { // call method present in actual class definition. No problem!!! m.printThickness(); // call newly defined method in Anonymous class. Compiler Error!!! m.hasLustre(); }}

Le code ci-dessus définit un métal de classe avec une seule méthode.
Cette classe est à nouveau implémentée de manière anonyme dans une autre classe MetalDriver où une nouvelle méthode est ajoutée à sa définition qui n’est pas présente dans la classe réelle.

Maintenant, lorsque cette nouvelle méthode est appelée, le compilateur se plaint d’une erreur

La méthode hasLuster() n’est pas définie pour le type Metal.

En effet, la classe anonyme est une sous-classe alors que la référence est de la classe réelle (qui est le parent).
Le compilateur n’a pas pu trouver la nouvelle méthode dans la classe parent et signale une erreur.

Ainsi, l’erreur établit deux faits:
(i) La classe anonyme est une sous-classe de la classe réelle, et
(ii) les définitions de classe anonyme suivent le polymorphisme.

Utilisation de la classe anonyme
Supposons que vous devez appeler une méthode qui prend un argument d’un type qui est une interface.
Maintenant, cette interface appartient à une bibliothèque externe et vous n’avez pas de classe qui implémente cette interface.
Comment allez-vous appeler cette méthode. Si vous passez null, il existe un risque d’exceptions de temps d’exécution.
Classe anonyme à la rescousse.
Maintenant, vous pouvez créer une classe anonyme qui implémente cette interface et la transmettre à la méthode en fournissant l’implémentation de ses méthodes selon vos besoins.L’exemple
suit.

// Interface from external Libraryinterface External { public void interfaceMethod();}class CalledClass { // Method to called. Takes an argument of interface type public void toBeCalled(External e) { e.interfaceMethod(); }}

Le code ci-dessus a une interface avec une seule méthode et une classe dont vous devez appeler la méthode à partir de votre code.La méthode

de cette classe prend un argument de type interface mais vous n’avez pas de classe qui implémente cette interface.
Si vous passez null à l’argument de la méthode, il lancera immédiatement un java.lang.NullPointerException.
Regardez comment vous pouvez appeler cette méthode en utilisant une classe anonyme.

class CallingClass { // Main method public static void main(String args) { CalledClass obj = new CalledClass(); // call method using Anonymous class obj.toBeCalled(new External() { public void interfaceMethod() { // your code } }); }}

Notez l’utilisation d’une implémentation d’interface anonyme pour appeler la méthode.
C’est le plus grand avantage des classes anonymes.
4. Classe imbriquée statique
Une classe statique définie dans une autre classe est une classe imbriquée statique. Il est défini comme une classe normale précédée d’un mot clé statique.
Rappelez-vous qu’il n’y a rien en tant que classe statique, une classe imbriquée statique n’est qu’un membre statique de sa classe externe.
Puisqu’il s’agit d’un membre statique, la suite s’applique à une classe imbriquée statique.

  1. Il est accessible directement par la classe externe sans avoir son instance.
  2. Il ne peut accéder qu’aux membres statiques de sa classe externe, mais pas à ses variables ou méthodes d’instance.

Exemple de classe imbriquée statique

public class Outer { // static nested class static class Inner { public void innerMethod() { System.out.println("Method of static nested class"); } } public void outerMethod() { System.out.println("Method of outer class"); } public static void main(String args) { // access inner class directly Inner inner = new Inner(); // call nested class method inner.innerMethod(); }}

Comme vous pouvez le voir dans l’exemple ci-dessus, pour accéder à la classe imbriquée statique, une instance de classe externe n’est pas requise et elle est accessible directement.
Notez que l’objet de la classe imbriquée statique ne peut pas accéder aux membres non statiques de la classe externe. Dans l’exemple ci-dessus, l’instance de classe imbriquée ne peut pas appeler outerMethod de la classe externe.

Ajustons

  1. Lorsqu’une classe contenant une classe interne est compilée, 2 fichiers de classe sont générés:
    un pour la classe externe et un pour la classe interne.Exemple
    , extérieur.classe et ExtérieurInnerIntérieur.classe pour la classe extérieure Classe extérieure et intérieure classe intérieure respectivement..
  2. Le fichier de classe de la classe interne ne peut pas être exécuté directement à l’aide de la commande java.
  3. Une classe interne normale ne peut pas avoir de membres de données ou de méthodes static.
  4. Une classe interne peut avoir un constructeur.
  5. Une classe locale de méthode ne peut être instanciée qu’à l’intérieur de la méthode dans laquelle elle est définie.
  6. Une classe locale de méthode définie dans la méthode static ne peut accéder qu’aux membres static de la classe englobante.
  7. Une classe anonyme qui implémente une interface ne peut implémenter qu’une seule interface par opposition aux classes normales qui peuvent en implémenter plusieurs.
  8. Une classe anonyme ne peut pas étendre une classe et implémenter une interface en même temps que les classes normales le peuvent.
  9. Les définitions de classe anonymes se terminent par }; (Notez le point-virgule).
  10. Les classes anonymes qui sont définies comme un argument lors de l’appel d’une méthode se terminent par }); (Notez le point-virgule).
  11. Vous ne pouvez pas appeler une méthode sur une référence de classe anonyme qui n’est pas présente dans la classe réelle.
  12. Une classe interne précédée de static est connue comme une classe imbriquée, pas une classe interne.

Leave a Reply