Héritage et polymorphisme en Java

JavaBeginner
Pratiquer maintenant

Introduction

Dans ce laboratoire, nous allons explorer deux concepts fondamentaux de la programmation orientée objet en Java : l'héritage et le polymorphisme. Ces fonctionnalités puissantes nous permettent de créer un code plus organisé, efficace et flexible. Nous commencerons par explorer l'héritage, qui nous permet de créer de nouvelles classes à partir de classes existantes, puis nous passerons au polymorphisme, qui nous permet de traiter les objets de différentes classes de manière uniforme.

À la fin de ce laboratoire, vous serez en mesure de :

  1. Créer des hiérarchies de classes en utilisant l'héritage
  2. Surcharger des méthodes dans les sous-classes
  3. Comprendre et utiliser le polymorphisme
  4. Implémenter des classes et des méthodes abstraites

Ne vous inquiétez pas si ces termes semblent complexes – nous allons tout décomposer en étapes simples et faciles à suivre. Commençons notre aventure passionnante pour améliorer vos compétences en programmation Java!

Ceci est un Guided Lab, qui fournit des instructions étape par étape pour vous aider à apprendre et à pratiquer. Suivez attentivement les instructions pour compléter chaque étape et acquérir une expérience pratique. Les données historiques montrent que c'est un laboratoire de niveau débutant avec un taux de réussite de 94%. Il a reçu un taux d'avis positifs de 100% de la part des apprenants.

Création d'une classe de base

Nous allons commencer par créer une classe de base appelée Animal. Cette classe servira de fondation pour nos autres classes.

  1. Ouvrez votre terminal et accédez au répertoire de votre projet :

    cd ~/project
  2. Créez un nouveau fichier appelé Animal.java en utilisant la commande touch :

    touch Animal.java
  3. Ouvrez le fichier Animal.java dans votre éditeur de texte et ajoutez le code suivant :

    public class Animal {
        private String name;
        private int age;
    
        public Animal(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void eat() {
            System.out.println(name + " is eating.");
        }
    
        public void sleep() {
            System.out.println(name + " is sleeping.");
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }

    Analysons ce code :

    • Nous définissons une classe nommée Animal avec deux attributs : name (une chaîne de caractères) et age (un entier).
    • Le mot clé private signifie que ces attributs ne peuvent être accédés qu'à l'intérieur de la classe.
    • Nous avons un constructeur qui initialise ces attributs lorsqu'un objet Animal est créé.
    • Nous avons deux méthodes : eat() et sleep(), qui affichent ce que l'animal est en train de faire.
    • Nous avons également des méthodes "getter" (getName() et getAge()) qui nous permettent d'accéder aux attributs privés depuis l'extérieur de la classe.
  4. Enregistrez le fichier Animal.java.

Enregistrement du fichier Animal.java
  1. Maintenant, compilons notre classe Animal pour nous assurer qu'il n'y a pas d'erreurs. Dans votre terminal, exécutez :

    javac Animal.java

    S'il n'y a pas de messages d'erreur, votre classe a été compilée avec succès!

Création d'une sous-classe

Maintenant que nous avons notre classe de base Animal, créons une sous-classe appelée Dog. Cela démontrera comment l'héritage fonctionne en Java.

  1. Dans votre terminal, créez un nouveau fichier appelé Dog.java :

    touch Dog.java
  2. Ouvrez Dog.java dans votre éditeur de texte et ajoutez le code suivant :

    public class Dog extends Animal {
        private String breed;
    
        public Dog(String name, int age, String breed) {
            super(name, age);  // Appel du constructeur de la superclasse
            this.breed = breed;
        }
    
        public String getBreed() {
            return breed;
        }
    }

    Décomposons ce nouveau code :

    • extends Animal indique à Java que Dog est une sous-classe de Animal. Bien que Dog hérite de Animal, les attributs privés name et age dans Animal ne sont pas directement accessibles dans Dog. Cependant, Dog peut accéder à ces attributs via les méthodes getter publiques héritées getName() et getAge().
    • Nous avons ajouté un nouvel attribut breed qui est spécifique à Dog.
    • Le constructeur prend trois paramètres. Il utilise super(name, age) pour appeler le constructeur Animal, puis définit le breed.
    • Nous avons ajouté une nouvelle méthode getBreed() qui est spécifique à Dog.
  3. Enregistrez le fichier Dog.java.

  4. Compilez la classe Dog :

    javac Dog.java

    Vous pourriez voir un avertissement concernant Animal.class, mais ce n'est pas grave pour l'instant.

Démonstration de l'héritage

Maintenant que nous avons nos classes Animal et Dog, créons un programme pour démontrer le fonctionnement de l'héritage.

  1. Créez un nouveau fichier appelé InheritanceDemo.java :

    touch InheritanceDemo.java
  2. Ouvrez le fichier InheritanceDemo.java et ajoutez le code suivant :

    public class InheritanceDemo {
        public static void main(String[] args) {
            Animal genericAnimal = new Animal("Generic Animal", 5);
            Dog myDog = new Dog("Buddy", 3, "Labrador");
    
            System.out.println("Demonstrating Animal class:");
            genericAnimal.eat();
            genericAnimal.sleep();
    
            System.out.println("\nDemonstrating Dog class:");
            myDog.eat();  // Hérité de la classe Animal
            myDog.sleep();  // Hérité de la classe Animal
    
            System.out.println("\nDog details:");
            System.out.println("Name: " + myDog.getName());  // Méthode héritée
            System.out.println("Age: " + myDog.getAge());  // Méthode héritée
            System.out.println("Breed: " + myDog.getBreed());  // Méthode spécifique à la classe Dog
        }
    }

    Ce programme crée des instances des classes Animal et Dog et montre comment la classe Dog hérite des méthodes de la classe Animal.

  3. Enregistrez le fichier InheritanceDemo.java.

  4. Compilez et exécutez le programme :

    javac InheritanceDemo.java
    java InheritanceDemo

    Vous devriez voir une sortie similaire à ceci :

    Demonstrating Animal class:
    Generic Animal is eating.
    Generic Animal is sleeping.
    
    Demonstrating Dog class:
    Buddy is eating.
    Buddy is sleeping.
    
    Dog details:
    Name: Buddy
    Age: 3
    Breed: Labrador

Cette démonstration montre comment la classe Dog hérite des attributs et des méthodes de la classe Animal, tout en ajoutant son propre attribut spécifique (breed) et sa propre méthode (getBreed()).

Redéfinition de méthode

La surcharge de méthode (method overriding) est une fonctionnalité qui permet à une sous-classe de fournir une implémentation spécifique d'une méthode déjà définie dans sa superclasse. Voyons comment cela fonctionne.

  1. Ouvrez le fichier Dog.java et ajoutez la méthode suivante :

    @Override
    public void eat() {
        System.out.println(getName() + " is eating dog food.");
    }

    Ajoutez cette méthode à l'intérieur de la classe Dog, mais en dehors de toute autre méthode.

    L'annotation @Override indique au compilateur que nous avons l'intention de surcharger une méthode de la superclasse. Elle n'est pas obligatoire, mais c'est une bonne pratique de l'utiliser.

  2. Enregistrez le fichier Dog.java.

  3. Maintenant, modifions notre fichier InheritanceDemo.java pour démontrer la surcharge de méthode. Ouvrez le fichier InheritanceDemo.java et remplacez son contenu par :

    public class InheritanceDemo {
        public static void main(String[] args) {
            Animal genericAnimal = new Animal("Generic Animal", 5);
            Dog myDog = new Dog("Buddy", 3, "Labrador");
    
            System.out.println("Demonstrating method overriding:");
            genericAnimal.eat();
            myDog.eat();
    
            System.out.println("\nDemonstrating inherited method:");
            myDog.sleep();  // Cette méthode est toujours héritée de la classe Animal
    
            System.out.println("\nDog details:");
            System.out.println("Name: " + myDog.getName());
            System.out.println("Age: " + myDog.getAge());
            System.out.println("Breed: " + myDog.getBreed());
        }
    }
  4. Enregistrez le fichier InheritanceDemo.java.

  5. Compilez et exécutez le programme mis à jour :

    javac Animal.java Dog.java InheritanceDemo.java
    java InheritanceDemo
Exemple de sortie de la surcharge de méthode

Vous devriez voir une sortie similaire à ceci :

Demonstrating method overriding:
Generic Animal is eating.
Buddy is eating dog food.

Demonstrating inherited method:
Buddy is sleeping.

Dog details:
Name: Buddy
Age: 3
Breed: Labrador

Cela démontre comment la surcharge de méthode permet à la classe Dog de fournir sa propre implémentation de la méthode eat(), tout en héritant d'autres méthodes telles que sleep() de la classe Animal.

Introduction au polymorphisme

Le polymorphisme est un concept fondamental en programmation orientée objet qui nous permet d'utiliser une référence de classe de base pour faire référence à un objet de sous-classe. Cela permet d'écrire un code plus flexible et réutilisable. Voyons comment cela fonctionne.

  1. Créez un nouveau fichier appelé Cat.java :

    touch Cat.java
  2. Ouvrez le fichier Cat.java et ajoutez le code suivant :

    public class Cat extends Animal {
        public Cat(String name, int age) {
            super(name, age);
        }
    
        @Override
        public void eat() {
            System.out.println(getName() + " is eating fish.");
        }
    
        public void meow() {
            System.out.println(getName() + " says: Meow!");
        }
    }

    Cela crée une autre sous-classe de Animal avec sa propre méthode eat() et une nouvelle méthode meow().

  3. Enregistrez le fichier Cat.java.

  4. Maintenant, mettons à jour notre fichier InheritanceDemo.java pour démontrer le polymorphisme. Remplacez son contenu par :

    public class InheritanceDemo {
        public static void main(String[] args) {
            Animal[] animals = new Animal[3];
            animals[0] = new Animal("Generic Animal", 5);
            animals[1] = new Dog("Buddy", 3, "Labrador");
            animals[2] = new Cat("Whiskers", 2);
    
            System.out.println("Demonstrating polymorphism:");
            for (Animal animal : animals) {
                animal.eat();  // Cela appellera la méthode eat() appropriée pour chaque animal
            }
    
            System.out.println("\nAccessing specific methods:");
            ((Dog) animals[1]).getBreed();  // Nous devons effectuer un cast en Dog pour appeler les méthodes spécifiques à Dog
            ((Cat) animals[2]).meow();      // Nous devons effectuer un cast en Cat pour appeler les méthodes spécifiques à Cat
        }
    }

    Ce code crée un tableau d'objets Animal, mais nous stockons en réalité un mélange d'objets Animal, Dog et Cat dedans. Lorsque nous appelons eat() sur chaque animal, Java appelle automatiquement la version appropriée de la méthode en fonction du type réel de l'objet.

  5. Enregistrez le fichier InheritanceDemo.java.

  6. Compilez et exécutez le programme mis à jour :

    javac Animal.java Dog.java Cat.java InheritanceDemo.java
    java InheritanceDemo

    Vous devriez voir une sortie similaire à ceci :

    Demonstrating polymorphism:
    Generic Animal is eating.
    Buddy is eating dog food.
    Whiskers is eating fish.
    
    Accessing specific methods:
    Whiskers says: Meow!

Cela démontre le polymorphisme en action. Nous sommes capables de traiter tous les objets comme des objets Animal, mais lorsque nous appelons la méthode eat(), chaque objet se comporte selon l'implémentation spécifique de sa classe.

Résumé

Dans ce laboratoire, nous avons exploré certains concepts clés de la programmation orientée objet en Java :

  1. Héritage : Nous avons créé une classe de base Animal et dérivé les classes Dog et Cat à partir d'elle. Cela nous a permis de réutiliser du code et de créer une hiérarchie logique de classes.
  2. Surcharge de méthode (Method Overriding) : Nous avons vu comment les sous-classes peuvent fournir leurs propres implémentations des méthodes définies dans la superclasse, permettant un comportement plus spécifique.
  3. Polymorphisme : Nous avons appris à traiter de manière uniforme les objets de différentes classes grâce à leur superclasse commune, ce qui permet d'écrire un code plus flexible et réutilisable.

Ces concepts sont fondamentaux en Java et en programmation orientée objet en général. Ils nous permettent de créer des structures de code plus organisées, efficaces et flexibles. Au fur et à mesure de votre progression dans l'apprentissage de Java, vous constaterez que ces concepts sont largement utilisés dans les applications plus complexes.

N'oubliez pas que la pratique est la clé pour maîtriser ces concepts.