Menu
Coddy logo textTech

Redéfinition de méthodes (Run-Time)

Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 29 sur 87.

Alors que la surcharge de méthodes est résolue au moment de la compilation, la redéfinition de méthode démontre le polymorphisme au moment de l'exécution. Ici, Java décide quelle méthode exécuter lorsque le programme est en cours d'exécution, en se basant sur le type réel de l'objet plutôt que sur le type déclaré de la variable.

Vous avez découvert la redéfinition de méthode (method overriding) dans le chapitre sur l'héritage. Ce qui la rend polymorphe, c'est la manière dont Java la gère lorsqu'une référence parente pointe vers un objet enfant :

public class Animal {
    public void speak() {
        System.out.println("Some sound");
    }
}

public class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Bark!");
    }
}

public class Cat extends Animal {
    @Override
    public void speak() {
        System.out.println("Meow!");
    }
}

Observez maintenant ce qui se passe lorsque nous utilisons des références de type parent :

Animal myPet = new Dog();
myPet.speak();  // Résultat : Bark!

myPet = new Cat();
myPet.speak();  // Résultat : Meow!

Même si myPet est déclaré comme Animal, Java appelle la méthode redéfinie en fonction du type réel de l'objet au moment de l'exécution. C'est ce qu'on appelle le dispatching dynamique de méthodes. La JVM regarde ce qu'est réellement l'objet, et non ce que la variable indique.

Cela permet des modèles puissants comme le traitement uniforme de différents objets :

Animal[] pets = {new Dog(), new Cat(), new Dog()};
for (Animal pet : pets) {
    pet.speak();  // Chacun appelle sa propre version
}

Le polymorphisme à l'exécution vous permet d'écrire du code flexible qui fonctionne avec des types parents tout en utilisant automatiquement le comportement enfant approprié.

challenge icon

Défi

Facile

Construisons un système de notification qui démontre le polymorphisme au moment de l'exécution. Vous allez créer une hiérarchie de types de notification où le même appel de méthode produit des sorties différentes selon le type d'objet réel au moment de l'exécution.

Vous organiserez votre code sur quatre fichiers :

  • Notification.java : Créez la classe de base que toutes les notifications partagent. Chaque notification possède un champ recipient (String). Incluez un constructeur pour l'initialiser, une méthode getter, et une méthode send() qui affiche : Sending notification to [recipient]
  • EmailNotification.java : Créez une classe qui étend Notification. Les notifications par e-mail ajoutent un champ subject. Utilisez super pour l'initialisation du parent. Surchargez la méthode send() pour afficher : Emailing [recipient]: [subject]
  • SMSNotification.java : Créez une autre classe qui étend Notification. Les notifications SMS ajoutent un champ phoneNumber. Surchargez send() pour afficher : Texting [phoneNumber] for [recipient]
  • Main.java : C'est ici que le polymorphisme au moment de l'exécution brille ! Vous recevrez trois entrées : un nom de destinataire, un sujet d'e-mail et un numéro de téléphone. Créez un tableau de références Notification contenant trois objets dans cet ordre : une Notification de base, une EmailNotification et une SMSNotification (utilisant toutes le même destinataire). Ensuite, parcourez le tableau et appelez send() sur chaque élément. Regardez comment Java appelle automatiquement la version surchargée correcte en fonction de ce qu'est réellement chaque objet !

Vous recevrez trois entrées : le nom du destinataire (String), le sujet de l'e-mail (String) et le numéro de téléphone (String).

Votre sortie devrait afficher trois lignes - chaque appel à send() produit une sortie différente même si vous appelez la même méthode sur des références Notification. C'est la répartition dynamique des méthodes à l'œuvre !

Aide-mémoire

La redéfinition de méthode démontre le polymorphisme au moment de l'exécution, où Java décide quelle méthode exécuter pendant que le programme tourne, en se basant sur le type réel de l'objet plutôt que sur le type déclaré de la variable.

Lorsqu'une référence parente pointe vers un objet enfant, Java appelle la méthode redéfinie en fonction du type d'objet réel au moment de l'exécution :

public class Animal {
    public void speak() {
        System.out.println("Some sound");
    }
}

public class Dog extends Animal {
    @Override
    public void speak() {
        System.out.println("Bark!");
    }
}

Animal myPet = new Dog();
myPet.speak();  // Output: Bark!

myPet = new Cat();
myPet.speak();  // Output: Meow!

C'est ce qu'on appelle la répartition dynamique des méthodes. La JVM regarde ce qu'est réellement l'objet, et non ce que dit la variable.

Le polymorphisme au moment de l'exécution permet de traiter différents objets de manière uniforme :

Animal[] pets = {new Dog(), new Cat(), new Dog()};
for (Animal pet : pets) {
    pet.speak();  // Chacun appelle sa propre version
}

Essayez vous-même

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // Lire les entrées
        String recipient = scanner.nextLine();
        String subject = scanner.nextLine();
        String phoneNumber = scanner.nextLine();
        
        // TODO: Créer un tableau de références Notification avec 3 éléments
        // Le tableau doit contenir (dans cet ordre) :
        // 1. Un objet Notification de base
        // 2. Un objet EmailNotification
        // 3. Un objet SMSNotification
        // Tous utilisant le même recipient
        
        // TODO: Parcourir le tableau et appeler send() sur chaque élément
        // Cela démontre le polymorphisme au moment de l'exécution !
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet