Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 22

"Utilisation de `super` pour les constructeurs et méthodes de la classe mère"

Recommended resources

Bonjour ! Dans la leçon précédente, nous avons posé les fondations de l'héritage avec le mot-clé extends, créant ainsi des hiérarchies de classes logiques. Vous avez eu un premier aperçu du mot-clé super en l'utilisant pour appeler le constructeur de la classe mère depuis la classe fille.

Aujourd'hui, nous allons approfondir notre maîtrise de ce mécanisme essentiel. L'objectif est de comprendre en détail les deux usages du mot-clé super : l'appel de constructeurs et l'appel de méthodes de la classe mère. Comprendre super est crucial, car c'est le "pont" qui connecte une classe fille à sa classe mère, garantissant une initialisation correcte et permettant de réutiliser et d'enrichir le code hérité.

1. Le chaînage des constructeurs avec super()

Lorsque vous créez une instance d'une classe fille, un processus appelé chaînage de constructeurs se met en place. Pour qu'un objet Voiture soit correctement construit, sa partie Vehicule doit d'abord être initialisée. De même, la partie Object (la classe mère de toutes les classes en Java) doit être initialisée en premier.

L'appel super(parametres) dans un constructeur de classe fille sert précisément à invoquer le constructeur de la classe mère pour qu'il initialise sa partie de l'objet.

Ce diagramme illustre parfaitement le processus. Lors de la création d'un objet `Client`, le constructeur de `Object` est appelé en premier (1), suivi de celui de `Person` (2), puis de celui de `Client` (3). Chaque constructeur est responsable d'initialiser les attributs de sa propre classe.

Pour bien comprendre les règles qui régissent ce mécanisme, la vidéo suivante du MOOC de l'EPFL est une excellente ressource.

Héritage : constructeurs

Cette vidéo académique explique en détail la nécessité et les règles de l'appel aux constructeurs de la super-classe.

Regardez les extraits suivants : Le problème de l'initialisation : Comprenez pourquoi le constructeur de la sous-classe doit initialiser les attributs hérités et comment il délègue cette tâche. Syntaxe de super() : Notez bien la syntaxe et la règle fondamentale : l'appel à super() doit être la toute première instruction du constructeur. L'appel implicite : Découvrez ce qu'il se passe si vous n'écrivez pas super() vous-même. Le compilateur ajoute un appel super(); implicite. Exemple concret : Voyez un exemple clair avec les classes FigureGeometrique et Rectangle. Résumé des règles : Cette partie résume les points essentiels à retenir.

Pour compléter, l'article ci-dessous formalise ces règles et montre les erreurs de compilation courantes, ce qui est très utile pour les éviter.

Mise en oeuvre du concept d'héritage - KooR.fr

Cet article du site Koor.fr détaille l'utilisation de super dans les constructeurs avec des exemples de code et met en évidence les erreurs fréquentes.

Lisez la section "Définition de constructeur et utilisation du mot clé super". Concentrez-vous sur les quatre règles énoncées, car elles résument tout ce que vous devez savoir. Ensuite, examinez les deux exemples de "Mauvaise utilisation des constructeurs" et les messages d'erreur associés. Comprendre pourquoi ce code ne compile pas est un excellent moyen de renforcer votre apprentissage.

En résumé, voici les règles d'or :

  1. L'appel à super(...) doit être la première instruction du constructeur de la classe fille.
  2. Si vous ne faites pas d'appel explicite, le compilateur insère super(); (appel au constructeur sans argument).
  3. Si la classe mère n'a pas de constructeur sans argument et que vous oubliez l'appel explicite, le code ne compilera pas. C'est une erreur très fréquente !

2. Accéder aux membres de la classe mère avec super.

Le mot-clé super a un second usage, tout aussi important. Que se passe-t-il si une classe fille redéfinit une méthode qui existait déjà dans la classe mère ? Par exemple, nous avons vu que toString() est souvent redéfinie.

Pour appeler la version de la méthode de la classe mère depuis la classe fille, on utilise la syntaxe super.nomDeLaMethode().

Ceci est extrêmement utile pour étendre le comportement de la classe mère, plutôt que de simplement le remplacer.

Ce schéma montre une classe `Dog` qui hérite d'`Animal`. Les deux ont une méthode `display()`. Depuis la classe `Dog`, `display()` fait référence à la méthode de `Dog`, tandis que `super.display()` fait explicitement référence à la méthode de la classe `Animal`.

Exemple pratique : Améliorer Employe.toString()

Dans l'exercice de la leçon précédente, la méthode toString() de notre objet Employe n'affichait que les informations de Personne. Nous allons maintenant la redéfinir dans Employe pour qu'elle affiche tout, en réutilisant le travail déjà fait dans Personne.

Classe Personne.java (inchangée)

public class Personne {
    protected String nom;
    protected String prenom;

    public Personne(String nom, String prenom) {
        this.nom = nom;
        this.prenom = prenom;
    }

    @Override
    public String toString() {
        return "Personne{" +
                "nom='" + nom + '\'' +
                ", prenom='" + prenom + '\'' +
                '}';
    }
}

Classe Employe.java (avec toString() amélioré)

public class Employe extends Personne {
    private String poste;
    private double salaire;

    public Employe(String nom, String prenom, String poste, double salaire) {
        // 1. Appel au constructeur de la classe mère
        super(nom, prenom); 
        this.poste = poste;
        this.salaire = salaire;
    }

    @Override
    public String toString() {
        // 2. Appel à la méthode toString() de la classe mère pour réutiliser son code
        String personneDetails = super.toString(); 

        // 3. On étend le résultat avec les informations propres à l'employé
        return personneDetails.replace("}", "") + // Astuce pour enlever l'accolade fermante
               ", poste='" + poste + '\'' +
               ", salaire=" + salaire +
               '}';
    }
}

Classe Main.java

public class Main {
    public static void main(String[] args) {
        Employe employe1 = new Employe("Durand", "Alice", "Développeuse Backend", 50000.0);
        System.out.println(employe1);
        // Affiche maintenant :
        // Personne{nom='Durand', prenom='Alice', poste='Développeuse Backend', salaire=50000.0}
    }
}

Cette technique est une bonne pratique professionnelle : elle évite la duplication de code et rend vos classes plus maintenables. Si vous modifiez le toString() de Personne, la modification sera automatiquement répercutée dans Employe.

La vidéo suivante explique clairement la distinction entre les deux usages de super.

JAVA (Intermédiaire) - 27 - Le mot clé super en Java

Cette vidéo de "LES TEACHERS DU NET" fait une démonstration claire des deux facettes du mot-clé super.

Regardez ces trois parties : super() pour les constructeurs : L'auteur montre comment appeler le constructeur parent et lui passer des paramètres. super. pour les membres : C'est la partie la plus importante. Elle montre comment accéder à un attribut ou une méthode de la classe mère lorsque la classe fille en a un(e) du même nom. Récapitulatif : Un résumé concis des deux usages.


3. Exercice de synthèse : Animal et Chien

Mettons maintenant tout cela en pratique avec un nouvel exercice.

Énoncé :

  1. Créez une classe mère Animal avec :

    • Un attribut protected String nom.
    • Un constructeur qui initialise le nom.
    • Une méthode public void seDeplacer() qui affiche "L'animal se déplace."
  2. Créez une classe fille Chien qui hérite de Animal.

    • Ajoutez un attribut private String race.
    • Créez un constructeur pour Chien qui initialise nom et race. Utilisez super() pour initialiser le nom via le constructeur d'Animal.
    • Redéfinissez la méthode seDeplacer() pour qu'elle affiche "Le chien court.".
    • Créez une nouvelle méthode public void aboyer() qui affiche "Wouaf !".
    • Créez une méthode public void afficherDetails() qui affiche le nom de l'animal (hérité) et sa race (spécifique).
  3. Dans une classe Main, créez une instance de Chien et appelez les méthodes seDeplacer(), aboyer() et afficherDetails().

Cliquez ici pour voir la solution

Classe Animal.java

public class Animal {
    protected String nom;

    public Animal(String nom) {
        this.nom = nom;
    }

    public void seDeplacer() {
        System.out.println("L'animal se déplace.");
    }
}

Classe Chien.java

public class Chien extends Animal {
    private String race;

    public Chien(String nom, String race) {
        // Appel au constructeur de la classe mère Animal
        super(nom);
        this.race = race;
    }

    @Override
    public void seDeplacer() {
        // On pourrait appeler la méthode parente si on voulait étendre le comportement :
        // super.seDeplacer(); 
        System.out.println("Le chien court.");
    }

    public void aboyer() {
        System.out.println("Wouaf !");
    }

    public void afficherDetails() {
        // 'nom' est accessible car il est protected dans Animal
        System.out.println("Nom: " + this.nom + ", Race: " + this.race);
    }
}

Classe Main.java

public class Main {
    public static void main(String[] args) {
        Chien monChien = new Chien("Médor", "Golden Retriever");

        monChien.seDeplacer();      // Affiche : Le chien court.
        monChien.aboyer();          // Affiche : Wouaf !
        monChien.afficherDetails(); // Affiche : Nom: Médor, Race: Golden Retriever
    }
}

Conclusion

Vous avez maintenant exploré en profondeur le mot-clé super, un outil indispensable dans l'arsenal du développeur Java orienté objet.

Points clés à retenir :

  • super(arguments) est utilisé pour appeler un constructeur de la classe mère. Ce doit être obligatoirement la première ligne du constructeur de la classe fille. Il assure le bon chaînage des initialisations.
  • super.membre est utilisé pour accéder à un attribut ou une méthode de la classe mère, notamment lorsqu'un membre de même nom existe dans la classe fille (cas de la redéfinition). Il permet d'étendre la fonctionnalité parente plutôt que de la remplacer purement et simplement.

Dans la prochaine leçon, nous allons nous appuyer sur les concepts d'héritage et de redéfinition pour aborder le polymorphisme. Vous découvrirez comment la redéfinition de méthodes avec @Override permet de créer du code incroyablement flexible et puissant, où des objets de différents types peuvent être traités de manière uniforme tout en conservant leur comportement spécifique.