Introduction
Les génériques en Java permettent d'écrire du code flexible et réutilisable en fournissant une couche supplémentaire d'abstraction. Elles permettent de créer un seul algorithme pour plusieurs types d'objets. Les génériques offrent une sécurité de type et évitent les erreurs de runtime. Dans ce laboratoire, nous allons comprendre divers aspects des génériques en Java.
Création d'une classe générique
Nous pouvons créer une classe générique en Java à l'aide de l'opérateur diament (<>). Dans le bloc de code suivant, nous allons créer une classe générique nommée MyGenericClass qui peut accepter n'importe quel type d'objet. Nous allons également créer un objet de type MyGenericClass avec des types entier et chaîne de caractères comme paramètres.
// ~/project/MyGenericClass.java
class MyGenericClass<T> {
T field1;
public MyGenericClass(T field1) {
this.field1 = field1;
}
public T getField1() {
return field1;
}
}
public class Main {
public static void main(String[] args) {
MyGenericClass<Integer> myIntObj = new MyGenericClass<Integer>(100);
MyGenericClass<String> myStringObj = new MyGenericClass<String>("Hello World");
System.out.println(myIntObj.getField1());
System.out.println(myStringObj.getField1());
}
}
Pour exécuter le code, ouvrez un terminal et accédez au répertoire ~/project. Compilez le code avec la commande suivante :
javac MyGenericClass.java
Après une compilation réussie, exécutez le code avec la commande suivante :
java Main
La sortie du code sera :
100
Hello World
Création d'une méthode générique
Nous pouvons également créer une méthode générique en Java. La méthode générique peut fonctionner avec différents types d'objets. Dans le bloc de code suivant, nous allons créer une méthode générique nommée printArray qui peut afficher n'importe quel type de tableau.
// ~/project/Main.java
public class Main {
public static <T> void printArray(T[] array) {
for (T element : array)
System.out.println(element);
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
Double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
String[] stringArray = {"Hello", "World"};
printArray(intArray);
printArray(doubleArray);
printArray(stringArray);
}
}
Pour exécuter le code, ouvrez un terminal et accédez au répertoire ~/project. Compilez le code avec la commande suivante :
javac Main.java
Après une compilation réussie, exécutez le code avec la commande suivante :
java Main
La sortie du code sera :
1
2
3
4
5
1.1
2.2
3.3
4.4
Hello
World
Création d'une méthode générique bornée
Nous pouvons également créer une méthode générique bornée. Les génériques bornés limitent la plage de types acceptés par la méthode. Nous utilisons le mot clé extends pour imposer la limite. Dans le bloc de code suivant, nous allons créer une méthode générique bornée nommée printNumbers qui peut afficher les nombres d'objets de type Number et de ses sous-classes.
// ~/project/Main.java
public class Main {
public static <T extends Number> void printNumbers(T[] numbers) {
for (T number : numbers)
System.out.println(number);
}
public static void main(String[] args) {
Integer[] intNumbers = {1, 2, 3, 4, 5};
Double[] doubleNumbers = {1.1, 2.2, 3.3, 4.4};
printNumbers(intNumbers);
printNumbers(doubleNumbers);
}
}
Pour exécuter le code, ouvrez un terminal et accédez au répertoire ~/project. Compilez le code avec la commande suivante :
javac Main.java
Après une compilation réussie, exécutez le code avec la commande suivante :
java Main
La sortie du code sera :
1
2
3
4
5
1.1
2.2
3.3
4.4
Comprendre la sécurité de type dans les génériques
Les génériques offrent une sécurité de type, en veillant à ce que nous ne définissions qu'un seul type d'objet avec lequel travailler à la fois. Dans le bloc de code suivant, nous allons créer une ArrayList d'entiers sans définir son paramètre de type. Il est une mauvaise pratique d'utiliser les génériques sans paramètres de type. Le code compilera, mais il retournera une erreur à l'exécution lorsque nous essaierons d'accéder à ses éléments de types différents.
// ~/project/Main.java
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList integerList = new ArrayList();
integerList.add(1);
integerList.add(2);
integerList.add(3);
integerList.add("Hello World");
for (Object element : integerList) {
System.out.println((Integer)element);
}
}
}
Pour exécuter le code, ouvrez un terminal et accédez au répertoire ~/project. Compilez le code avec la commande suivante :
javac Main.java
Après une compilation réussie, exécutez le code avec la commande suivante :
java Main
La sortie du code sera :
1
2
3
Exception in thread "main" java.lang.ClassCastException: java.base/java.lang.String cannot be cast to java.base/java.lang.Integer
at Main.main(Main.java:13)
Nous obtenons une erreur à l'exécution car la integerList contient des éléments des types Integer et String. Cela est dû au fait que nous n'avons pas défini le paramètre de type lors de la création de la integerList.
Comprendre l'effacement de type dans les génériques
Java utilise l'effacement de type dans les génériques pour s'assurer qu'aucune surcharge supplémentaire n'est nécessaire à l'exécution. Le compilateur remplace le paramètre de type par la classe Object ou la classe parente (en cas de génériques bornés) pendant le processus d'effacement de type. Dans le bloc de code suivant, nous allons voir comment les génériques fonctionnent avec les types primitifs à la compilation et à l'exécution.
// ~/project/Main.java
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> integerList = new ArrayList<Integer>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
int sum = 0;
for (int i = 0; i < integerList.size(); i++) {
sum += integerList.get(i);
}
System.out.println(sum);
}
}
Pour exécuter le code, ouvrez un terminal et accédez au répertoire ~/project. Compilez le code avec la commande suivante :
javac Main.java
Après une compilation réussie, exécutez le code avec la commande suivante :
java Main
La sortie du code sera :
6
Dans le bloc de code ci-dessus, nous avons essayé d'ajouter les éléments de la integerList. Comme nous le savons, les types primitifs comme int ne peuvent pas être utilisés avec les génériques. En raison de l'effacement de type, le paramètre de type Integer est remplacé par la classe Object à la compilation. Cependant, l'autoboxing et l'unboxing nous ont permis de réaliser l'addition d'entiers à la compilation. À l'exécution, le code s'est exécuté comme un code normal, sans aucune surcharge supplémentaire.
Résumé
Dans ce laboratoire, nous avons appris les notions de base relatives aux génériques Java. Nous avons abordé les concepts fondamentaux liés aux classes génériques, aux méthodes génériques, aux méthodes génériques bornées, à la sécurité de type dans les génériques et à l'effacement de type dans les génériques. Nous avons également vu comment écrire du code flexible et réutilisable en utilisant les génériques. Nous espérons que ce laboratoire vous a aidé à comprendre les génériques en Java.



