Tutoriel Java Generics - Que sont les génériques et comment les utiliser?

Java Generics est l'une des fonctionnalités les plus importantes du langage Java. L'idée derrière les génériques est assez simple, cependant, elle se révèle parfois complexe en raison du changement de la syntaxe habituelle qui lui est associée.

Le but de ce didacticiel est de vous présenter ce concept utile de génériques d'une manière facile à comprendre.

Mais avant de plonger dans les génériques eux-mêmes, voyons pourquoi les génériques Java étaient nécessaires en premier lieu.




Objectif des génériques Java

Avant l'introduction des génériques dans Java 5, vous pouviez écrire et compiler un extrait de code comme celui-ci sans générer d'erreur ni d'avertissement:

List list = new ArrayList(); list.add('hey'); list.add(new Object());

Vous pouvez ajouter des valeurs de n'importe quel type à une liste ou à une autre collection Java sans avoir à déclarer le type de données qu'elle stocke. Mais lorsque vous récupérez des valeurs de la liste, vous devez les convertir explicitement en un certain type.


Pensez à parcourir la liste ci-dessus.

for (int i=0; i< list.size(); i++) {
String value = (String) list.get(i); //CastClassException when i=1 }

Autoriser la création d'une liste sans déclarer au préalable le type de données stocké, comme nous l'avons fait, pourrait amener les programmeurs à faire des erreurs comme ci-dessus qui lève ClassCastExceptions pendant l'exécution.

Des génériques ont été introduits pour empêcher les programmeurs de faire de telles erreurs.

Avec les génériques, vous pouvez déclarer explicitement le type de données qui sera stocké lors de la création d'une collection Java, comme le montre l'exemple suivant.


Noter:Vous pouvez toujours créer un objet de collection Java sans spécifier le type de données stocké, mais cela n'est pas recommandé. List stringList = new ArrayList();

Désormais, vous ne pouvez pas stocker par erreur un Integer dans une liste de type String sans générer une erreur de compilation. Cela garantit que votre programme ne rencontre pas d'erreurs d'exécution.

stringList.add(new Integer(4)); //Compile time Error

Le but principal de l'introduction des génériques dans Java était d'éviter de se heurter à ClassCastExceptions pendant l'exécution.



Création de génériques Java

Vous pouvez utiliser des génériques pour créer des classes et des méthodes Java. Examinons des exemples de création de génériques de chaque type.

Classe générique

Lors de la création d'une classe générique, le paramètre de type de la classe est ajouté à la fin du nom de la classe dans l'angle supports.


public class GenericClass {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return this.item;
} }

Ici, T est le paramètre de type de données. T, N et E sont quelques-unes des lettres utilisées pour les paramètres de type de données selon les conventions Java.

Dans l'exemple ci-dessus, vous pouvez lui transmettre un type de données spécifique lors de la création d'un objet GenericClass.

public static void main(String[] args) {
GenericClass gc1 = new GenericClass();
gc1.setItem('hello');
String item1 = gc1.getItem(); // 'hello'
gc1.setItem(new Object()); //Error
GenericClass gc2 = new GenericClass();
gc2.setItem(new Integer(1));
Integer item2 = gc2.getItem(); // 1
gc2.setItem('hello'); //Error }

Vous ne pouvez pas transmettre un type de données primitif au paramètre de type de données lors de la création d'un objet de classe générique. Seuls les types de données qui étendent le type d'objet peuvent être passés en tant que paramètres de type.

Par example:


GenericClass gc3 = new GenericClass(); //Error

Méthodes génériques

La création de méthodes génériques suit un modèle similaire à la création de classes génériques. Vous pouvez implémenter une méthode générique dans une classe générique ou non générique.

public class GenericMethodClass {
public static void printItems(T[] arr){
for (int i=0; i< arr.length; i++) {

System.out.println(arr[i]);
}
}
public static void main(String[] args) {
String[] arr1 = {'Cat', 'Dog', 'Mouse'};
Integer[] arr2 = {1, 2, 3};

GenericMethodClass.printItems(arr1); // 'Cat', 'Dog', 'Mouse'
GenericMethodClass.printItems(arr2); // 1, 2, 3
} }

Ici, vous pouvez passer un tableau d'un type spécifique pour paramétrer la méthode. La méthode générique PrintItems() itère dans le tableau passé et imprime les éléments stockés comme une méthode Java normale.



Paramètres de type borné

Jusqu'à présent, les classes et méthodes génériques que nous avons créées ci-dessus peuvent être paramétrées sur n'importe quel type de données autre que les types primitifs. Mais que se passerait-il si nous voulions limiter les types de données pouvant être transmis aux génériques? C'est là qu'interviennent les paramètres de type borné.

Vous pouvez lier les types de données acceptés par une classe ou une méthode générique en spécifiant qu'il doit s'agir d'une sous-classe d'un autre type de données.


Par example:

//accepts only subclasses of List public class UpperBoundedClass{
//accepts only subclasses of List
public void UpperBoundedMethod(T[] arr) {
} }

Ici, le UpperBoundedClass et UpperBoundedMethod ne peut être paramétré qu'à l'aide des sous-types de List Type de données.

List le type de données agit comme une limite supérieure du paramètre type. Si vous essayez d'utiliser un type de données qui n'est pas un sous-type de List, une erreur de compilation sera générée.

Les limites ne sont pas limitées aux seules classes. Vous pouvez également transmettre des interfaces. Étendre l'interface signifie, dans ce cas, implémenter l'interface.

Un paramètre peut également avoir plusieurs limites comme le montre cet exemple.

//accepts only subclasses of both Mammal and Animal public class MultipleBoundedClass{
//accepts only subclasses of both Mammal and Animal
public void MultipleBoundedMethod(T[] arr){
} }

Le type de données acceptant doit être une sous-classe des classes d'animaux et de mammifères. Si l'une de ces bornes est une classe, elle doit venir en premier dans la déclaration liée.

Dans l'exemple ci-dessus, si Mammal est une classe et Animal est une interface, Mammal doit venir en premier comme indiqué ci-dessus. Sinon, le code renvoie une erreur de compilation.



Caractères génériques Java

Les caractères génériques sont utilisés pour transmettre des paramètres de types génériques aux méthodes. Contrairement à une méthode générique, ici, le paramètre générique est passé aux paramètres acceptés par la méthode, ce qui est différent du paramètre de type de données décrit ci-dessus. Un joker est représenté par le? symbole.

public void printItems(List list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
} }

Ce qui précède printItems() La méthode accepte des listes de tout type de données comme paramètre. Cela évite aux programmeurs d'avoir à répéter des codes pour des listes de différents types de données, ce qui serait le cas sans génériques.

Caractères génériques délimités supérieurs

Si nous voulons limiter les types de données stockés dans la liste acceptée par la méthode, nous pouvons utiliser des jokers bornés.

Exemple:

public void printSubTypes(List list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
} }

printSubTypes() n'accepte que les listes qui stockent des sous-types de couleur. Il accepte une liste d'objets RedColor ou BlueColor, mais n'accepte pas une liste d'objets Animal. C'est parce que Animal n'est pas un sous-type de couleur. Ceci est un exemple de caractère générique à limite supérieure.

Caractères génériques délimités inférieurs

De même, si nous avions:

public void printSuperTypes(List list) {
for (int i=0; i< list.size(); i++) {
System.out.println(list.get(i));
} }

puis, le printSuperTypes() La méthode n'accepte que les listes qui stockent les super types de la classe Dog. Il accepterait une liste d'objets Mammal ou Animal mais pas une liste d'objets LabDog car LabDog n'est pas une superclasse de Dog, mais une sous-classe. Ceci est un exemple de caractère générique à limite inférieure.



Conclusion

Java Generics est devenu une fonctionnalité dont les programmeurs ne peuvent se passer depuis son introduction.

Cette popularité est due à son impact sur la simplification de la vie des programmeurs. En plus de les empêcher de faire des erreurs de codage, l'utilisation de génériques rend le code moins répétitif. Avez-vous remarqué comment il généralise les classes et les méthodes pour éviter d'avoir à répéter le code pour différents types de données?

Avoir une bonne maîtrise des génériques est important pour devenir un expert de la langue. Donc, appliquer ce que vous avez appris dans ce didacticiel dans un code pratique est la voie à suivre maintenant.