Skip to content
18 Polymorphisme

Polymorphisme

Le polymorphisme est la capacité d’objets de classes différentes à réagir différemment aux même messages (appels de méthodes).

Par exemple, une méthode makeSound() que l’on peut appeler sur n’importe quel animal. Chaque animal à sa propre façon de faire du bruit. Pour le développeur, ce n’est qu’un appel ä animal.makeSound() mais ce qui se passe dépent du type effectif de l’objet référencer par cette variable.


Types de polymorphisme

En Java, il existe plusieurs types de polymorphisme

Polymorphisme de compilation - overloading

Il s’agit du cas où une classe contient plusieurs méthodes portant le même nom mais ayant des paramètres différents. Le compilateur décide lui même quelle méthode appeler en fonction des arguments fournis.

class Printer {
    void print(int x) {
        System.out.println("Nombre : " + x);
    }

    void print(String s) {
        System.out.println("Chaîne : " + s);
    }
}

Polymorphisme d’exécution - overriding

Un comportement défini dans la classe parent est redéfinis dans les sous classes. La méthode effectivement apelée est choisit à l’exécution, selon le type effectif de l’objet.

class Animal {
    void makeSound() {
        System.out.println("Un son quelconque...");
    }
}

// chaque sous classe viens modifier le comportement initial
class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Ouaf !");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Miaou !");
    }
}

class Cow extends Animal {
    @Override
    void makeSound() {
        System.out.println("Meuh !");
    }
}

// utilisation
Animal animal1 = new Dog();
Animal animal2 = new Cat();
Animal animal3 = new Cow();

animal1.makeSound(); // Ouaf !
animal2.makeSound(); // Miaou !
animal3.makeSound(); // Meuh !

Intéret du polymorphisme

Le polymorphisme permet de rendre le code flexible, extensible et facile à maintenir.

Il permet d’écrire du code qui travail avec des objets du type de base, sans avoir à se soucier des détails de leur implémentation Par exemple, avec une liste d’animaux, on peut venir itérer et appeler makeSound() sur chacun, sans avoir besoin de se demander quel est le type d’animal

Animal[] animals = { new Dog(), new Cat(), new Cow() };

for (Animal animal : animals) {
    animal.makeSound(); // À chaque fois, c’est la « bonne » méthode qui sera appelée
}

Cela permet de simplifier les extension. Par exemple, on souhaite ajouter un animal, on viens étendre la classe parent. Tout le restee reste inchangée. C’est le principe ouvert à l’extension et fermé à la modification.


Surcharge de méthode

La surcharge de méthode est la possibilité de déclarer dans une mêne classe plusieurs méthodes portant le même nom mais avec des listes de paramètres différentes (type, nombre ou ordre des arguments). Lorsque l’on appelle ce type de méthodem le compilateur décide lui-même quelle version utiliser en fonction des arguments transmis.

La surcharge se distingue uniquement par la liste de paramètres.

public class Printer {
    // Affichage d'un entier
    void print(int x) {
        System.out.println("int: " + x);
    }

    // Affichage d'une chaîne
    void print(String s) {
        System.out.println("String: " + s);
    }

    // Affichage de deux nombres
    void print(int x, int y) {
        System.out.println("int, int: " + x + ", " + y);
    }
}

// utilisation 
Printer printer = new Printer();
printer.print(42);           // appellera print(int x)
printer.print("Hello!");     // appellera print(String s)
printer.print(5, 10);        // appellera print(int x, int y)

Surcharge des constructeurs

Il est également possible de faire une surcharge des constructeurs

public class Person {
    String name;
    int age;

    // Constructeur avec uniquement le nom
    public Person(String name) {
        this.name = name;
        this.age = 0; // par défaut
    }

    // Constructeur avec nom et âge
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// utilisation 
Person p1 = new Person("Anna");
Person p2 = new Person("Boris", 25);

Surcharge et varargs (nombre variable d’arguments)

Il est possible de déclarer une méthode avec un nombre variable de paramètres avec ...

void printAll(String... messages) {
    for (String msg : messages) {
        System.out.println(msg);
    }
}

// utilisation 
printAll("Hello");
printAll("One", "Two", "Three");

Redéfinition de méthode

La redéfinition est possible dans les classes enfant. Elle pernet d’écrire sa propre implémentation de méthode déjà présente dans la classe parent.

class Animal {
    void makeSound() {
        System.out.println("L’animal émet un son");
    }
}

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Ouaf !");
    }
}

class Cat extends Animal {
    @Override
    void makeSound() {
        System.out.println("Miaou !");
    }
}

Utilisation du polymorphisme

Polymorphisme dans les collections

On peut avoir une classe Animal avec un ensemble de classe enfant: Cat, Dog, Cow

Au lieu de créer des tabeaux séparés pour chaque animal, on peut déclarer un tableau de type Animal et y placer des objets de chaque type.

Animal[] animals = {
    new Dog(),
    new Cat(),
    new Cow(),
    new Parrot()
};

On peut ensuite venir itérer ce tableau, et appeller la méthode de chaque classe

for (Animal animal : animals) {
    animal.makeSound();
}