Classes génériques
Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 54 sur 87.
Maintenant que vous comprenez pourquoi les génériques sont utiles, créons votre propre classe générique. Une classe générique déclare un ou plusieurs paramètres de type entre chevrons après le nom de la classe, qui peuvent ensuite être utilisés dans toute la classe.
class Box<T> {
private T content;
public void set(T content) {
this.content = content;
}
public T get() {
return content;
}
}Le T est un paramètre de type — un espace réservé qui est remplacé par un type réel lorsque vous créez une instance. Vous pouvez utiliser n'importe quel nom, mais les lettres majuscules uniques sont conventionnelles : T pour Type, E pour Élément, K pour Clé, V pour Valeur.
Lors de l'instanciation d'une classe générique, vous spécifiez le type réel entre chevrons :
Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get(); // Aucun transtypage nécessaire
Box<Integer> intBox = new Box<>();
intBox.set(42);
Integer num = intBox.get();Remarquez l'<> (opérateur diamant) sur le côté droit — Java déduit le type à partir de la déclaration. Vous pouvez également utiliser plusieurs paramètres de type pour les classes qui doivent fonctionner avec plus d'un type :
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
Pair<String, Integer> pair = new Pair<>("age", 25);Défi
FacileConstruisons un système de registre de cadeaux qui illustre la puissance des classes génériques. Vous allez créer un système de stockage flexible capable de contenir n'importe quel type d'article de cadeau, ainsi qu'un registre qui associe les noms des cadeaux à leurs détails en utilisant plusieurs paramètres de type.
Vous organiserez votre code sur trois fichiers :
GiftBox.java: Créez une classe générique capable d'emballer n'importe quel type de cadeau. VotreGiftBox<T>doit avoir un champ privéitemde typeTet un champ privéwrapped(booléen) qui commence àfalse. Incluez un constructeur qui accepte l'article, une méthodegetItem()qui retourne l'article, une méthodewrap()qui définit wrapped à true, et une méthodeisWrapped()qui retourne l'état d'emballage. Ajoutez une méthodegetStatus()qui retourne soit[item] (wrapped)soit[item] (unwrapped)selon l'état d'emballage.Registry.java: Créez une classe générique avec deux paramètres de type qui associe un destinataire à son cadeau. VotreRegistry<K, V>doit avoir des champs privésrecipientde typeKetgiftde typeV. Incluez un constructeur qui accepte les deux valeurs, des méthodes gettergetRecipient()etgetGift(), et une méthodegetEntry()qui retourne :[recipient] -> [gift]Main.java: Donnez vie à votre registre de cadeaux ! Vous recevrez trois entrées : un nom de destinataire (String), une description de cadeau (String) et une valeur de cadeau (entier représentant des dollars).Tout d'abord, créez un
GiftBox<String>contenant la description du cadeau. Emballez-le en utilisant la méthodewrap(), puis affichez son statut.Ensuite, créez un
GiftBox<Integer>contenant la valeur du cadeau (représentant le montant d'une carte-cadeau). N'emballez pas celui-ci — affichez son statut pour montrer qu'il n'est pas emballé.Enfin, créez un
Registry<String, String>associant le nom du destinataire à la description du cadeau, et affichez l'entrée du registre.
Vous recevrez trois entrées dans l'ordre : le nom du destinataire, la description du cadeau et la valeur du cadeau (sous forme d'entier).
Remarquez comment la même classe GiftBox fonctionne parfaitement avec les types String et Integer — c'est toute la beauté des génériques ! Et la classe Registry démontre comment plusieurs paramètres de type vous permettent de créer des associations flexibles entre n'importe quels deux types.
Aide-mémoire
Une classe générique déclare un ou plusieurs paramètres de type entre chevrons après le nom de la classe, lesquels peuvent être utilisés dans toute la classe :
class Box<T> {
private T content;
public void set(T content) {
this.content = content;
}
public T get() {
return content;
}
}Le T est un paramètre de type — un espace réservé remplacé par un type réel lors de la création d'une instance. Les conventions courantes utilisent des lettres majuscules uniques : T pour Type, E pour Element, K pour Key, V pour Value.
Lors de l'instanciation d'une classe générique, spécifiez le type réel entre chevrons :
Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get(); // No casting needed
Box<Integer> intBox = new Box<>();
intBox.set(42);
Integer num = intBox.get();L'opérateur <> (diamond operator) permet à Java d'inférer le type à partir de la déclaration.
Utilisez plusieurs paramètres de type pour les classes qui travaillent avec plus d'un type :
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public V getValue() { return value; }
}
Pair<String, Integer> pair = new Pair<>("age", 25);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 recipientName = scanner.nextLine();
String giftDescription = scanner.nextLine();
int giftValue = scanner.nextInt();
// TODO: Créer un GiftBox<String> contenant la description du cadeau
// TODO: L'emballer en utilisant la méthode wrap()
// TODO: Afficher son statut en utilisant getStatus()
// TODO: Créer un GiftBox<Integer> contenant la valeur du cadeau
// TODO: Ne pas emballer celui-ci - afficher son statut (devrait indiquer non emballé)
// TODO: Créer un Registry<String, String> associant le destinataire à la description du cadeau
// TODO: Afficher l'entrée du registre en utilisant getEntry()
}
}
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
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesChamps (Attributs)Méthode constructeurSurcharge de constructeurRécapitulatif - Calculatrice simple4Héritage
Héritage de base (extends)Le mot-clé superRedéfinition de méthode (@Override)Chaînage de constructeursLa classe ObjectHéritage simple et multiniveauPourquoi pas d'héritage multiple de classesRécapitulatif - Hiérarchie des employés7Méthodes spéciales et classe Object
Méthode toString()equals() et hashCode()Méthode clone()compareTo() et ComparableInterface ComparatorRécapitulatif - Tri personnalisé2Modificateurs d'accès et Encapsulation
Aperçu des niveaux d'accèsMéthodes Getter et SetterMasquage d'informationsLe mot-clé finalRécapitulatif - Gestionnaire de compte bancaire5Polymorphisme
Bases de la surcharge de méthodesRedéfinition de méthodes (Run-Time)Upcasting et DowncastingL'opérateur instanceofClasses et méthodes abstraitesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageAgrégation vs CompositionClasses internes, imbriquées et anonymesEnums et méthodes d'EnumRecords (Java 16+)Classes scellées (Java 17+)11Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron MonteurPatron ObservateurPatron Stratégie3Propriétés de classe et membres statiques
Variables d'instance vs variables statiquesMéthodes statiquesBlocs statiquesConstantes (static final)Récapitulatif - Compteur et utilitaire6Interfaces et Classes Abstraites
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesDefault et Static dans les InterfacesClasses Abstraites vs InterfacesInterfaces FonctionnellesRécapitulatif - Système de Paiement9La généricité
Introduction à la généricitéClasses génériquesMéthodes génériquesParamètres de type bornésWildcards (?, extends, super)Récapitulatif - Conteneur générique12Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositePatron Itérateur