CodeGym/Blog Java/Random-FR/Exemples d'héritage de classes imbriquées
Auteur
Oleksandr Miadelets
Head of Developers Team at CodeGym

Exemples d'héritage de classes imbriquées

Publié dans le groupe Random-FR
membres
Salut! Aujourd'hui, nous allons nous intéresser à un mécanisme important : l'héritage dans les classes imbriquées. Avez-vous déjà pensé à ce que vous feriez si vous deviez faire en sorte qu'une classe imbriquée hérite d'une autre classe. Sinon, croyez-moi : cette situation peut prêter à confusion, car il y a beaucoup de nuances.
  1. Sommes-nous en train de faire hériter une classe imbriquée d'une classe ? Ou faisons-nous hériter une classe d'une classe imbriquée ?
  2. La classe enfant/parent est-elle une classe publique ordinaire, ou est-ce également une classe imbriquée ?
  3. Enfin, quel type de classes imbriquées utilisons-nous dans toutes ces situations ?
Il y a tellement de réponses possibles à toutes ces questions que vous aurez la tête qui tourne :) Comme vous le savez, on peut résoudre un problème complexe en le divisant en parties plus simples. Faisons cela. Considérons tour à tour chaque groupe de classes imbriquées sous deux angles : qui peut hériter de chaque type de classe imbriquée, et de qui elle peut hériter. Commençons par les classes imbriquées statiques.

Classes imbriquées statiques

Exemples d'héritage de classes imbriquées - 2Leurs règles d'héritage sont les plus simples. Ici, vous pouvez faire presque tout ce que votre cœur désire. Une classe imbriquée statique peut hériter :
  • une classe ordinaire
  • une classe imbriquée statique qui est déclarée dans une classe externe ou ses ancêtres
Rappelez-vous un exemple de notre leçon sur les classes imbriquées statiques.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Essayons de changer le code et de créer une Drawingclasse imbriquée statique et son descendant — Boeing737Drawing.
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Comme vous pouvez le voir, pas de problème. Nous pouvons même extraire la Drawingclasse et en faire une classe publique ordinaire au lieu d'une classe imbriquée statique - rien ne changera.
public class Drawing {

}

public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Boeing737Drawing extends Drawing {

       public static int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Nous comprenons cela. Mais quelles classes peuvent hériter d'une classe imbriquée statique ? Pratiquement n'importe lequel ! Imbriqué/non imbriqué, statique/non statique — cela n'a pas d'importance. Ici, nous faisons en sorte que la Boeing737Drawingclasse interne hérite de la Drawingclasse imbriquée statique :
public class Boeing737 {

   private int manufactureYear;
   private static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }

   public class Boeing737Drawing extends Drawing {

       public int getMaxPassengersCount() {

           return maxPassengersCount;
       }
   }
}
Vous pouvez créer une instance Boeing737Drawingcomme celle-ci :
public class Main {

   public static void main(String[] args) {

      Boeing737 boeing737 = new Boeing737(1990);
      Boeing737.Boeing737Drawing drawing = boeing737.new Boeing737Drawing();
      System.out.println(drawing.getMaxPassengersCount());

   }

}
Bien que notre Boeing737Drawingclasse hérite d'une classe statique, elle n'est pas statique elle-même ! Par conséquent, il aura toujours besoin d'une instance de la classe externe. Nous pouvons supprimer la Boeing737Drawingclasse de la Boeing737classe et en faire une simple classe publique. Rien ne change. Il peut toujours hériter de la Drawingclasse imbriquée statique.
public class Boeing737 {

   private int manufactureYear;
   public static int maxPassengersCount = 300;

   public Boeing737(int manufactureYear) {
       this.manufactureYear = manufactureYear;
   }

   public int getManufactureYear() {
       return manufactureYear;
   }

   public static class Drawing {

   }
}

public class Boeing737Drawing extends Boeing737.Drawing {

   public int getMaxPassengersCount() {

       return Boeing737.maxPassengersCount;

}
Le seul point important est que dans ce cas, nous devons rendre maxPassengersCountpublique la variable statique. S'il reste privé, une classe publique ordinaire n'y aura pas accès. Nous avons compris les classes statiques ! :) Passons maintenant aux classes internes. Ils sont de 3 types : les classes internes simples, les classes locales et les classes internes anonymes. Exemples d'héritage de classes imbriquées - 3Encore une fois, passons du simple au complexe :)

Classes internes anonymes

Une classe interne anonyme ne peut pas hériter d'une autre classe. Aucune autre classe ne peut hériter d'une classe anonyme. Rien de plus simple ! :)

Cours locaux

Les classes locales (au cas où vous l'auriez oublié) sont déclarées dans un bloc de code d'une autre classe. Le plus souvent, cela se produit à l'intérieur d'une méthode de la classe externe. Logiquement, seules les autres classes locales à l'intérieur de la même méthode (ou bloc de code) peuvent hériter d'une classe locale. Voici un exemple:
public class PhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class PhoneNumber {

           private String phoneNumber;

           public PhoneNumber() {
               this.phoneNumber = number;
           }

           public String getPhoneNumber() {
               return phoneNumber;
           }

           public void setPhoneNumber(String phoneNumber) {
               this.phoneNumber = phoneNumber;
           }
       }

       class CellPhoneNumber extends PhoneNumber {

       }

       class LandlinePhoneNumber extends PhoneNumber {


       }

       // ...number validation code
   }
}
C'est le code de notre leçon sur les classes locales. Notre classe de validateur de nombre a une PhoneNumberclasse locale. Si nous en avons besoin pour représenter deux entités distinctes, par exemple, un numéro de téléphone mobile et un numéro de téléphone fixe, nous ne pouvons le faire qu'à l'intérieur de la même méthode. La raison est simple : la portée d'une classe locale est limitée à la méthode (bloc de code) où elle est déclarée. Par conséquent, nous ne pourrons pas l'utiliser en externe (y compris pour l'héritage de classe). Cependant, les possibilités d'héritage au sein de la classe locale elle-même sont beaucoup plus larges ! Une classe locale peut hériter :
  1. Une classe ordinaire.
  2. Une classe interne qui est déclarée dans la même classe que la classe locale ou dans l'un de ses ancêtres.
  3. Une autre classe locale déclarée dans la même méthode (bloc de code).
Les premier et troisième points semblent évidents, mais le second est un peu déroutant :/ Regardons deux exemples. Exemple 1 — "Faire hériter une classe locale d'une classe interne déclarée dans la même classe que la classe locale":
public class PhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       // ...number validation code
   }
}
Ici, nous avons supprimé la PhoneNumberclasse de la validatePhoneNumber()méthode et en avons fait une classe interne au lieu d'une classe locale. Cela ne nous empêche pas d'en faire hériter nos 2 classes locales. Exemple 2 — "... ou dans les ancêtres de cette classe." Maintenant, c'est déjà plus intéressant. On peut monter PhoneNumberencore plus haut dans la chaîne d'héritage. Déclarons une AbstractPhoneNumberValidatorclasse abstraite, qui deviendra l'ancêtre de notre PhoneNumberValidatorclasse :
public abstract class AbstractPhoneNumberValidator {

   class PhoneNumber {

       private String phoneNumber;

       public PhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }

       public String getPhoneNumber() {
           return phoneNumber;
       }

       public void setPhoneNumber(String phoneNumber) {
           this.phoneNumber = phoneNumber;
       }
   }

}
Comme vous pouvez le voir, nous ne nous sommes pas contentés de le déclarer, nous PhoneNumbery avons également déplacé la classe interne. Cependant, dans son descendant PhoneNumberValidator, les classes locales déclarées dans les méthodes peuvent hériter PhoneNumbersans problème !
public class PhoneNumberValidator extends AbstractPhoneNumberValidator {

   public void validatePhoneNumber(final String number) {

       class CellPhoneNumber extends PhoneNumber {

           public CellPhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       class LandlinePhoneNumber extends PhoneNumber {

           public LandlinePhoneNumber(String phoneNumber) {
               super(number);
           }
       }

       // ...number validation code
   }
}
En raison de la relation d'héritage, les classes locales à l'intérieur d'une classe descendante "voient" les classes internes à l'intérieur d'un ancêtre. Et enfin, passons au dernier groupe :)

Classes intérieures

Une classe interne déclarée dans la même classe externe (ou dans sa descendante) peut hériter d'une autre classe interne. Explorons cela en utilisant notre exemple avec des vélos de la leçon sur les classes internes.
public class Bicycle {

   private String model;
   private int maxWeight;

   public Bicycle(String model, int maxWeight) {
       this.model = model;
       this.maxWeight = maxWeight;
   }

   public void start() {
       System.out.println("Let's go!");
   }

   class Seat {

       public void up() {

           System.out.println("Seat up!");
       }

       public void down() {

           System.out.println("Seat down!");
       }
   }

   class SportSeat extends Seat {

       // ...methods
   }
}
Ici, nous avons déclaré la Seatclasse interne à l'intérieur de la Bicycleclasse. Un type spécial de siège de course, SportSeat, en hérite. Mais, nous pourrions créer un type "vélo de course" distinct et le mettre dans une classe distincte :
public class SportBicycle extends Bicycle {

   public SportBicycle(String model, int maxWeight) {
       super(model, maxWeight);
   }


   class SportSeat extends Seat {

       public void up() {

           System.out.println("Seat up!");
       }

       public void down() {

           System.out.println("Seat down!");
       }
   }
}
C'est aussi une option. La classe interne du descendant ( SportBicycle.SportSeat) "voit" les classes internes de l'ancêtre et peut en hériter. L'héritage des classes internes a une caractéristique très importante ! Dans les deux exemples précédents, notre SportSeatclasse était une classe interne. Mais que se passe-t-il si nous décidons de créer SportSeatune classe publique ordinaire qui hérite simultanément de la Seatclasse interne ?
// Error! No enclosing instance of type 'Bicycle' is in scope
class SportSeat extends Bicycle.Seat {

   public SportSeat() {

   }

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
Nous avons une erreur ! Pouvez-vous deviner pourquoi? :) Tout est simple. Lorsque nous avons parlé de la Bicycle.Seatclasse interne, nous avons mentionné qu'une référence à une instance de la classe externe est passée implicitement au constructeur de la classe interne. Cela signifie que vous ne pouvez pas créer un Seatobjet sans créer un Bicycleobjet. Mais qu'en est-il de la création d'un SportSeat? Contrairement à Seat, il n'a pas ce mécanisme intégré pour transmettre implicitement au constructeur une référence à une instance de la classe externe. Pourtant, sans Bicycleobjet, nous ne pouvons pas créer d' SportSeatobjet, tout comme dans le cas de Seat. Par conséquent, il ne nous reste plus qu'une chose à faire : passer explicitement au SportSeatconstructeur une référence à un Bicycleobjet. Voici comment procéder :
class SportSeat extends Bicycle.Seat {

   public SportSeat(Bicycle bicycle) {

       bicycle.super();
   }

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
Nous appelons le constructeur de la superclasse en utilisant super(); Now, si nous voulons créer un SportSeatobjet, rien ne nous empêchera de le faire :
public class Main {

   public static void main(String[] args) {

       Bicycle bicycle = new Bicycle("Peugeot", 120);
       SportSeat peugeotSportSeat = new SportSeat(bicycle);

   }
}
Phew! Cette leçon a été plutôt longue :) Mais tu as beaucoup appris ! Il est maintenant temps de résoudre certaines tâches ! :)
Commentaires
  • Populaires
  • Nouveau
  • Anciennes
Tu dois être connecté(e) pour laisser un commentaire
Cette page ne comporte pas encore de commentaires