Classes et méthodes génériques
Ce serait bien si nous pouvions écrire une seule méthode de tri permettant de trier les éléments d'un tableau Integer, d'un tableau String ou d'un tableau de tout type prenant en charge l'ordre.
Les méthodes et les classes génériques permettent aux programmeurs de spécifier, avec une seule déclaration de méthode, un ensemble de méthodes associées, ou avec une seule déclaration de classe, un ensemble de types associés, respectivement.
Les génériques offrent également une sécurité de type compile-time qui permet aux programmeurs d’attraper les types invalides au moment de la compilation.
Méthodes génériques
Vous pouvez écrire une seule déclaration de méthode générique pouvant être appelée avec des arguments de types différents. En fonction des types d'arguments transmis à la méthode générique, le compilateur gère chaque appel de méthode de manière appropriée.
Voici les règles pour définir des méthodes génériques
- Toutes les déclarations de méthode génériques ont une section de paramètre de type délimitée par des crochets (< et >) qui précède le type de retour de la méthode (<E> dans l'exemple suivant).
- Chaque section de paramètre de type contient un ou plusieurs paramètres de type séparés par des virgules. Un paramètre de type, aussi appelé variable de type, est un identifiant qui spécifie un nom de type générique.
- Les paramètres de type peuvent être utilisés pour déclarer le type de retour et agir comme des espaces réservés pour les types d'arguments passés à la méthode generic, qui sont connus comme des arguments de type réels.
- Le corps d'une méthode générique est déclaré comme n'importe quelle autre méthode. Notez que les paramètres de type ne peuvent représenter que des types de référence, pas des types primitifs (tels que int, double et char).
Exemple 1 :
public class Test { public < E> void afficher(E[] tab) { for (E elem : tab) { System.out.print(elem + ", "); } System.out.println(""); } public static void main(String args[]) { Test ts = new Test(); Integer[] T1 = { 1, 4, 5 }; Double[] T2 = { 2.4, 5.7, 7.0 }; String[] T3 = { "Mostafa", "Ismail", "Kaoutar" }; ts.afficher(T1); ts.afficher(T2); ts.afficher(T3); } }
2.4, 5.7, 7.0,
Mostafa, Ismail, Kaoutar,
Nous pouvons également transmettre plusieurs paramètres de type
Exemple 2 :
public class Test { public < E, T> void afficher(E p1, T p2) { System.out.println(p1 + " - " + p2); } public static void main(String args[]) { Test ts = new Test(); Integer a = 2; Double b = 3.5; ts.afficher(a, b); } }
Paramètres de type borné
Il peut y avoir des moments où vous voudrez restreindre les types qui peuvent être passés à un paramètre type. Par exemple, une méthode qui fonctionne sur des nombres pourrait ne vouloir accepter que des instances de Number ou ses sous-classes. C'est à cela que servent les paramètres de type borné.
Pour déclarer un paramètre de type borné, indiquez le nom du paramètre de type, suivi du mot-clé extends, suivi de sa limite supérieure.
L'exemple suivant illustre l'utilisation, de façon générale, par extends (comme dans les classes) ou "implements" (comme dans les interfaces). Cet exemple est une méthode générique pour renvoyer le plus grand des trois objets comparables
Exemple 3 :
public class Test { public < T extends Comparable< T>> T maximum(T x, T y, T z) { T max = x; if (y.compareTo(max) > 0) { max = y; } if (z.compareTo(max) > 0) { max = z; } return max; } public static void main(String args[]) { Test ts = new Test(); System.out.println("(2,7,5); le max est : " + ts.maximum(2, 7, 5)); System.out.println("(6.35,2.6,1.25); le max est : " + ts.maximum(6.35, 2.6, 1.25)); } }
(6.35,2.6,1.25); le max est : 6.35
Classes génériques
Une déclaration de classe générique ressemble à une déclaration de classe non générique, sauf que le nom de la classe est suivi d'une section de paramètre de type.
Comme pour les méthodes génériques, la section des paramètres de type d'une classe générique peut avoir un ou plusieurs paramètres de type séparés par des virgules. Ces classes sont appelées classes paramétrées ou types paramétrés car elles acceptent un ou plusieurs paramètres.
Exemple 4 :
public class Test< T> { private T attribut; private Double val; public Test(T attribut, Double val) { this.attribut = attribut; this.val = val; } public T getAttribut() { return attribut; } public void setAttribut(T attribut) { this.attribut = attribut; } public Double getVal() { return val; } public void setVal(Double val) { this.val = val; } public static void main(String args[]) { Test< Integer> T1 = new Test< Integer>(2, 3.5); System.out.println("T1.attribut " + T1.getAttribut()); Test< String> T2 = new Test< String>("Mostafa", 3.5); System.out.println("T2.attribut " + T2.getAttribut()); } }
T2.attribut Mostafa
Avantages de classes et méthodes génériques
Les programmes utilisant un code générique présentent de nombreux avantages par rapport au code non générique.
- Réutilisation de code: Nous pouvons écrire une méthode/ classe/interface une fois et les utiliser pour tout type souhaité.
- Sécurisé des types: Les génériques font apparaître des erreurs au moment de la compilation qu'au moment de l'exécution.
- typage (casting) n'est pas nécessaire : Le typage à chaque opération de récupération est un gros problème. Si nous savons déjà que une liste ne contient que des données de type String, nous n'avons pas besoin de faire le typage à chaque fois.