Menu
Coddy logo textTech

Wildcards (?, extends, super)

Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy. Leçon 57 sur 87.

Les paramètres de type bornés restreignent les types génériques à des types spécifiques, mais que faire lorsque vous travaillez avec des types génériques existants et que vous ne connaissez pas, ou que vous ne vous souciez pas, du paramètre de type exact ? C’est là que les caractères génériques entrent en jeu.

Le joker non borné ? représente un type inconnu. Il est utile lorsque vous souhaitez accepter n’importe quel type paramétré :

public static void printList(List<?> list) {
    for (Object item : list) {
        System.out.println(item);
    }
}

printList(new ArrayList<String>());   // Fonctionne
printList(new ArrayList<Integer>());  // Fonctionne

Le joker à borne supérieure ? extends Type accepte le type spécifié ou l’une de ses sous-classes. Utilisez-le lorsque vous devez lire depuis une structure générique :

public static double sumNumbers(List<? extends Number> numbers) {
    double sum = 0;
    for (Number n : numbers) {
        sum += n.doubleValue();
    }
    return sum;
}

sumNumbers(Arrays.asList(1, 2, 3));        // Liste d'Integer
sumNumbers(Arrays.asList(1.5, 2.5));       // Liste de Double

Le joker à borne inférieure ? super Type accepte le type spécifié ou l’une de ses superclasses. Utilisez-le lorsque vous devez écrire dans une structure générique :

public static void addIntegers(List<? super Integer> list) {
    list.add(1);
    list.add(2);
}

List<Number> numbers = new ArrayList<>();
addIntegers(numbers);  // Fonctionne - Number est un supertype de Integer

Une directive utile : utilisez extends lorsque vous faites uniquement de la lecture (producteur), et utilisez super lorsque vous faites uniquement de l’écriture (consommateur). C’est ce que l’on appelle le principe PECS : Producer Extends, Consumer Super.

challenge icon

Défi

Facile

Construisons un système d’alimentation pour un zoo qui illustre les trois types de jokers ! Vous allez créer une hiérarchie d’animaux et de nourriture, puis écrire des méthodes utilitaires qui utilisent des jokers non bornés, à borne supérieure et à borne inférieure pour gérer différents scénarios d’alimentation.

Vous organiserez votre code sur quatre fichiers :

  • Food.java : créez une hiérarchie de classes simple pour la nourriture. Commencez par une classe de base Food qui possède un champ privé name (String), un constructeur pour l’initialiser et une méthode getName(). Créez ensuite deux sous-classes dans le même fichier : Meat extends Food (le constructeur appelle super(name)) et Vegetable extends Food (même principe).
  • Animal.java : créez une classe de base Animal avec un champ privé species (String), un constructeur et une méthode getSpecies(). Créez deux sous-classes : Carnivore et Herbivore, qui étendent chacune Animal et appellent le constructeur parent.
  • ZooFeeder.java : c’est ici que les jokers révèlent toute leur utilité ! Créez une classe utilitaire avec trois méthodes statiques :

    printInventory(List<?> items) - Utilise un joker non borné pour afficher n’importe quelle liste. Parcourez-la et affichez chaque élément à l’aide de toString(), un par ligne.

    calculateTotalFood(List<? extends Food> foods) - Utilise un joker à borne supérieure pour lire une liste contenant n’importe quel type de Food. Retournez le nombre d’éléments sous la forme d’un int. Cela illustre la lecture depuis un producteur.

    addMeatToStock(List<? super Meat> stock, String meatName) - Utilise un joker à borne inférieure pour écrire dans une liste pouvant contenir des objets Meat. Créez un nouvel objet Meat avec le nom fourni et ajoutez-le au stock. Cela illustre l’écriture dans un consommateur.

  • Main.java : assemblez votre système d’alimentation du zoo ! Vous recevrez deux entrées : un nom de viande (String) et un nom de légume (String).

    Commencez par créer un ArrayList<Food> et ajoutez un objet Meat portant le nom de la viande ainsi qu’un objet Vegetable portant le nom du légume. Affichez Food inventory:, puis appelez printInventory avec cette liste.

    Ensuite, affichez une ligne vide, puis affichez Total food items: [count] en utilisant calculateTotalFood sur votre liste de nourriture.

    Enfin, créez un nouvel ArrayList<Food> appelé meatStock. Affichez une ligne vide, puis Adding to meat stock.... Appelez addMeatToStock avec cette liste et la chaîne "Beef". Affichez ensuite Meat stock after adding: et appelez printInventory sur le stock de viande.

Vous recevrez deux entrées dans l’ordre : un nom de viande et un nom de légume.

Redéfinissez toString() dans votre classe Food afin qu’elle retourne le nom de la nourriture, pour que l’affichage fonctionne correctement. Remarquez comment chaque type de joker sert un objectif différent : ? pour une flexibilité maximale lorsque vous devez simplement lire en tant qu’Object, ? extends lors de la lecture de types spécifiques et ? super lors de l’écriture dans une collection !

Essayez vous-même

import java.util.Scanner;
import java.util.ArrayList;
import java.util.List;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String meatName = scanner.nextLine();
        String vegetableName = scanner.nextLine();
        
        // TODO: Créez un ArrayList<Food> et ajoutez des objets Meat et Vegetable
        
        // TODO: Print "Food inventory:" then call printInventory
        
        // TODO: Print blank line, then "Total food items: [count]" using calculateTotalFood
        
        // TODO: Créez un nouveau ArrayList<Food> appelé meatStock
        
        // TODO: Print blank line, then "Adding to meat stock..."
        
        // TODO: Appelez addMeatToStock avec meatStock et "Beef"
        
        // TODO: Print "Meat stock after adding:" then call printInventory on meatStock
    }
}
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

Entraînez-vous par vous-même : Compilateur Java en ligne