Keyboard shortcuts

Touchez ← ou → pour naviguer les chapitres

Touchez S ou / pour chercher dans le livre

Touchez ? pour afficher ce message

Touchez Esc pour masquer ce message

Accueil > Programmation orientée objet >

📚 HĂ©ritage et polymorphisme

Survol et attentes

En créant des logiciels plus complexes, plusieurs objets peuvent avoir des caractéristiques communes. Par exemple, un jeu vidéo peut avoir plusieurs types de personnages, mais tous les personnages ont des caractéristiques communes comme la position, la vitesse, la direction, etc. Dans ce cas, il est utile de créer une classe de base qui contient les caractéristiques communes, puis de créer des classes dérivées qui contiennent les caractéristiques spécifiques à chaque type de personnage.

Définitions

L’hĂ©ritage nous perment de dĂ©clarer une classe parente qui contient des attributs et des mĂ©thodes communes Ă  plusieurs classes enfants.

Les classes enfants hĂ©ritent des attributs et des mĂ©thodes de la classe parente. Les classes enfants peuvent supplanter la dĂ©finition d’une mĂ©thode de la classe parente, comme on l’a dĂ©jĂ  vu avec les mĂ©thodes toString(), equals()ethashCode()`. Elles peuvent aussi avoir leurs propres attributs et mĂ©thodes.

Seulement les attributs de visibilitĂ© protected ou public d’une classe parent seront hĂ©ritĂ©s par les enfants. La nouvelle visibilitĂ© protected est comme private sauf pour les membres de la mĂȘme famille. Donc, les attributs private de la classe parent appartiennent uniquement au parent tandis que les attributs protected seront hĂ©ritĂ©s.

Notez que la visibilitĂ© par dĂ©faut (sans dĂ©claration explicite) est package-private qui est comme public Ă  l’intĂ©rieur du package et comme private Ă  l’extĂ©rieur. Vous ne pouvez pas explicitement dĂ©clarer quelque chose package-private
 simplement n’utilisez pas de mot-clĂ© si vous voulez ce niveau de visibilitĂ©.

Exemples et solutions

Une classe enfant indique son lien de parentĂ© en utilisant le mot-clĂ© extends dans sa dĂ©claration. Par exemple, la classe Warrior peut ĂȘtre dĂ©clarĂ©e comme suit :

public class Warrior extends Player {
    // ...
}

Une classe enfant peut rĂ©utiliser le constructeur de sa classe parente en utilisant la mĂ©thode super() dans son constructeur. Par exemple, la classe Warrior peut ĂȘtre dĂ©clarĂ©e comme suit :

public class Warrior extends Player {
    public Warrior(String name, int health, int strength) {
        super(name, health, strength);
    }
}

présumant que la classe Player a déclarée un constructeur comme suit :

public class Player {
    protected String name;
    protected int health;
    protected int strength;

    public Player(String name, int health, int strength) {
        this.name = name;
        this.health = health;
        this.strength = strength;
    }
}

Le mot-clĂ© super() s’applique aux autres mĂ©thodes de la classe parente Ă©galement. S’il est utilisĂ©, ça doit toujours ĂȘtre la premiĂšre instruction dans la mĂ©thode de la classe enfant qui supplante la mĂ©thode originale.

Dans un diagramme de classe UML, on indique la relation d’hĂ©ritage avec une ligne solide et une tĂȘte de flĂšche en triangle pointant vers la classe parente. Par exemple, les classes Warrior, Wizard et Healer hĂ©ritent toutes de la classe Player :

heritage1

Relation “est un”

L’hĂ©ritage est une relation “est un”. Par exemple, un Warrior est un Player. On peut donc utiliser un objet de type Warrior partout oĂč un objet de type Player est attendu. Par exemple, on peut dĂ©clarer une variable de type Player et lui assigner un objet de type Warrior ou Ă  d’autres types qui sont des extensions de Player :

ArrayList<Player> players = new ArrayList<>();
players.add(new Warrior("Conan", 90, 10));
players.add(new Wizard("Gandalf", 50, 5));
players.add(new Healer("Rowena", 100, 2));

La liste est dĂ©clarĂ©e comme une liste de Player, mais on peut y ajouter des objets de type Warrior, Wizard et Healer parce que ces classes “sont des” Player via l’hĂ©ritage. Quand les objets de type parent pointent Ă  des instances de type enfant, cela s’appelle le polymorphisme. Le polymorphisme fait spĂ©cifiquement rĂ©fĂ©rence Ă  la capacitĂ© d’appeler la mĂȘme mĂ©thode sur des objets de types diffĂ©rents et d’obtenir des rĂ©sultats diffĂ©rents : cette mĂ©thode a plusieurs formes, littĂ©ralement la dĂ©finition de polymorphisme.

La vidĂ©o suivante prĂ©sente un bon portrait du polymorphisme possible via l’hĂ©ritage, soit celui qui est possible en prenant des types enfants pour le type parent : đŸ“ș Upcasting et downcasting

Objectifs d’apprentissage

À la fin de cette leçon vous devrez ĂȘtre en mesure de :

  • Comprendre et expliquer le concept d’hĂ©ritage, notamment en connaissant le sens des termes classe parente, classe enfant, et des mots-clĂ© extends et super en Java.
  • Comprendre et expliquer le concept de polymorphisme, notamment en connaissant la relation “est un”.
  • Identifier la classe parente et la classe enfant dans un diagramme de classe UML.

CritĂšres de succĂšs

  • Je peux dĂ©clarer une classe enfant qui hĂ©rite d’une classe parente
  • Je peux rĂ©utiliser le code pertienent de la classe parente avec le mot-clĂ© super et supplanter les mĂ©thodes de la classe parente avec du code plus appropriĂ©.
  • Je peux dĂ©clarer une variable de type parent et lui assigner un objet de type enfant.

Exercices

Quiz de validation des connaissances

Travail pratique :

  1. Créer les fichiers appropriés pour les classes suivantes et remarquez ce qui se passe en lançant la classe App :

    public class Parent {
        String name;
    
        Parent(String name) {
            this.name = name;
        }
    
        void role() {
            System.out.print("I'm the ");
        }
    
        void sayName() {
            System.out.println("My name is " + name);
        }
    
    }
    
    public class Dad extends Parent {
    
        Dad(String name) {
            super(name);
        }
    
        @Override
        void role() {
            super.role(); // toujours en premier... réutilise le code de la classe parente
            System.out.println("dad.");
        }
    
        @Override // supplante (prend priorité sur) la version dans la classe parente
        void sayName() {
            System.out.println("My name is Mr. " + name + ".");
        }
    }
    
    public class App {
        public static void main(String[] args) {
            Dad dad = new Dad("John");
            dad.role();
            dad.sayName();
        }
    }
    
  2. Créer deux classes Mom et LegalGuardian qui héritent de Parent et qui modifient le code hérité de maniÚre appropriée. Ajouter des déclarations dans la classe App pour tester votre code.

  3. Préparer un diagramme de classe UML pour les classes Parent, Dad, Mom et LegalGuardian et vérifier votre diagramme avec votre enseignant(e).

© 2022-2025 David Crowley