Le Tutoriel de Java Generics
1. Pourquoi Java Generics?
Generics est un concept qui est mis en Java depuis la version 5. Avant de vous instroduire de la notion de Generics, on voit un extrait de code Java avant la version 5.
Dans cet exemple, ArrayList est une liste dans laquelle vous pouvez ajouter, supprimer, modifier la liste et accéder aux éléments de la liste.
BeforeJ5Example.java
package org.o7planning.tutorial.generics;
import java.util.ArrayList;
public class BeforeJ5Example {
public static void main(String[] args) {
// Créer un objet ArrayList (une liste).
// Pour contenir le nom de l'utilisateur
ArrayList userNames = new ArrayList();
// Ajouter les String à la liste.
userNames.add("tom");
userNames.add("jerry");
// Vous avez accidentellement ajouté un élément non type String à la liste.
// (Ceci est absolument permis).
userNames.add(new Integer(100));
// Et sortir le premier élément
// C'est un objet (mais vous savez que c'est un String)
// ==> tom
Object obj1 = userNames.get(0);
// Presser type (cast) au String
String userName1 = (String) obj1;
System.out.println("userName1 = " + userName1);
// Sortir le deuxième élément
// (vous savez que c'est String)
// ==> jerry
String userName2 = (String) userNames.get(1);
System.out.println("userName2 = " + userName2);
// Sortir le troisième élément et presser le type (cast) au String
// (En fait, c'est un Integer).
// (L'erreur typographique se produit ici).
String userName3 = (String) userNames.get(2);
System.out.println("userName3 = " + userName3);
}
}
Une situation en Java avant la version 5 :
Vous créez un objet ArrayList dans le but de ne contenir que des éléments avec le type de String, mais vous ajoutez à cette liste un élément qui n'est pas de type String dans quelque part du programme (Ceci est tout à fait possible) lorsque vous sortez de cet éléments et forcez en type de String, une exception sera levée.
Vous créez un objet ArrayList dans le but de ne contenir que des éléments avec le type de String, mais vous ajoutez à cette liste un élément qui n'est pas de type String dans quelque part du programme (Ceci est tout à fait possible) lorsque vous sortez de cet éléments et forcez en type de String, une exception sera levée.
- TODO (Image)
Java 5 met en concept de Generics. Avec l'aide de Generics, vous pouvez créer un objet ArrayList qui ne permet que de contenir des éléments avec le type de String et ne permet pas de contenir des éléments avec d'autres types.
J5Example.java
package org.o7planning.tutorial.generics;
import java.util.ArrayList;
public class J5Example {
public static void main(String[] args) {
// Créer un ArrayList (Une liste)
// Cette liste ne permet que contenir des éléments du type String.
ArrayList<String> userNames = new ArrayList<String>();
// Ajouter des String à la liste.
userNames.add("tom");
userNames.add("jerry");
// Vous ne pouvez pas ajouter un élément qui n'est pas une String à la liste.
// (L'erreur se produit lors de la compilation).
userNames.add(new Integer(100)); // Compile Error!
// Vous n'avez pas besoin de forcer l'élément sur le type (cast).
String userName1 = userNames.get(0);
System.out.println("userName1 = " + userName1);
}
}
Lorsque vous créez un objet ArrayList<String> qui ne contient que des éléments de type String, le compilateur Java ne permet pas à cet objet de contenir d'autres éléments de type String.
2. Type Generic pour Class & Interface
Generics Class
L'exemple ci-dessous définit une classe generics.KeyValue est une classe génériques qui contient une paire clé / valeur (clé/valeur).
KeyValue.java
package org.o7planning.tutorial.generics.ci;
public class KeyValue<K, V> {
private K key;
private V value;
public KeyValue(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
K, V dans la classe KeyValue <K, V> est appelé paramètre générique qui est un certain type de référence. Lorsque vous utilisez cette classe, vous devez déterminer le paramètre spécifique.
Prennez l'exemple qui utilise la classe KeyValue.
Prennez l'exemple qui utilise la classe KeyValue.
KeyValueDemo.java
package org.o7planning.tutorial.generics.ci;
public class KeyValueDemo {
public static void main(String[] args) {
// Créer l'object KeyValue
// Integer : Le numéro de téléphone (K = Integer)
// String : Le nom de l'utilisateur. (V = String).
KeyValue<Integer, String> entry = new KeyValue<Integer, String>(12000111, "Tom");
// Java comprend le type de retour qui est Integer
// (K = Integer).
//
Integer phone = entry.getKey();
// Java comprend le type de retour qui est String
// (V = String).
String name = entry.getValue();
System.out.println("Phone = " + phone + " / name = " + name);
}
}
Exécutez l'exemple :
Phone = 12000111 / name = Tom
Héritage de la Classe Generics
Une classe étendue à partir d'une classe générique peut spécifier le type de paramètre des génériques, peut conserver les paramètres génériques ou ajouter des paramètres génériques.
Exemple 1:
PhoneNameEntry.java
package org.o7planning.tutorial.generics.ci;
// Cette classe étend (extends) de la classe KeyValue==<==K,V>.
// Et spécifie uniquement K,V :
// K = Integer (Le numéro de téléphone).
// V = String (Le nom de l'utilisateur).
public class PhoneNameEntry extends KeyValue<Integer, String> {
public PhoneNameEntry(Integer key, String value) {
super(key, value);
}
}
L'exemple utilise PhoneNameEntry :
PhoneNameEntryDemo.java
package org.o7planning.tutorial.generics.ci;
public class PhoneNameEntryDemo {
public static void main(String[] args) {
PhoneNameEntry entry = new PhoneNameEntry(12000111, "Tom");
// Java comprend que le type de retour qui est Integer.
Integer phone = entry.getKey();
// Java comprend que le type de retour qui est String.
String name = entry.getValue();
System.out.println("Phone = " + phone + " / name = " + name);
}
}
Exemple 2:
StringAndValueEntry.java
package org.o7planning.tutorial.generics.ci;
// Cette classe étend (extends) de classe KeyValue==<==K,V>.
// Spécifie le paramètre de type <K> est String.
// Garde toujours le type de paramètre Generic <V>.
public class StringAndValueEntry<V> extends KeyValue<String, V> {
public StringAndValueEntry(String key, V value) {
super(key, value);
}
}
L'exemple utilise la classe StringAndValueEntry :
StringAndValueEntryDemo.java
package org.o7planning.tutorial.generics.ci;
public class StringAndValueEntryDemo {
public static void main(String[] args) {
// (Le code de l'employé, le nom de l'employé).
// V = String (Nom de l'employé)
StringAndValueEntry<String> entry = new StringAndValueEntry<String>("E001", "Tom");
String empNumber = entry.getKey();
String empName = entry.getValue();
System.out.println("Emp Number = " + empNumber);
System.out.println("Emp Name = " + empName);
}
}
Exemple 3:
KeyValueInfo.java
package org.o7planning.tutorial.generics.ci;
// Cette classe s'étend (extends) de la classe KeyValue <K, V>
// Il ajoute un paramètre Generics <I>.
public class KeyValueInfo<K, V, I> extends KeyValue<K, V> {
private I info;
public KeyValueInfo(K key, V value) {
super(key, value);
}
public KeyValueInfo(K key, V value, I info) {
super(key, value);
this.info = info;
}
public I getInfo() {
return info;
}
public void setInfo(I info) {
this.info = info;
}
}
Generics Interface
Une Interface a des paramètres Générics :
GenericInterface.java
package org.o7planning.tutorial.generics.ci;
public interface GenericInterface<G> {
public G doSomething();
}
Par exemple, une classe met en œuvre sur l'interface au-dessous :
GenericInterfaceImpl.java
package org.o7planning.tutorial.generics.ci;
public class GenericInterfaceImpl<G> implements GenericInterface<G>{
private G something;
@Override
public G doSomething() {
return something;
}
}
Java ne soutient pas Generic Throwable
Vous ne pouvez pas créer une classe générique qui est descendante de Throwable, car java ne soutient pas de la création de telle classe.
Le message d'erreur du compilateur :
- The generic class MyException<E> may not subclass java.lang.Throwable
Java ne soutient pas de la création d'une classe générique Throwable car elle n'apporte aucun avantage. La raison en est que l'information Generic n'est utilisée qu'au compilateur de contrôleur de code des programmeurs. Dans l'exécution de Java, les informations génériques n'existent pas, un objet de Mistake <Account> ou Mistake <User> est un type d'objet de Mistake.
} catch( Mistake<Account> ea) {
// Si l'exception Mistake se produit, ce bloc sera exécuté.
...
} catch( Mistake<User> eu) {
//
// Ce bloc n'est jamais exécuté
...
}
3. Méthode generics
Une méthode dans la classe ou de l'interface peut être produits génériques (generify).
MyUtils.java
package org.o7planning.tutorial.generics.m;
import java.util.ArrayList;
import org.o7planning.tutorial.generics.ci.KeyValue;
public class MyUtils {
// <K,V> : Pour dire que cette méthode a deux paramètres K, V
// La méthode renvoie un objet du type K.
public static <K, V> K getKey(KeyValue<K, V> entry) {
K key = entry.getKey();
return key;
}
// <K,V> : Pour dire que cette méthode a deux paramètres K, V
// La méthode renvoie un objet de type V.
public static <K, V> V getValue(KeyValue<K, V> entry) {
V value = entry.getValue();
return value;
}
// ArrayList<E>: La liste contient les éléments du type E.
// La méthode renvoie un objet du type E.
public static <E> E getFirstElement(ArrayList<E> list) {
if (list == null || list.isEmpty()) {
return null;
}
E first = list.get(0);
return first;
}
}
Par exemple, l'utilisation de la méthode generics :
MyUtilsDemo.java
package org.o7planning.tutorial.generics.m;
import java.util.ArrayList;
import org.o7planning.tutorial.generics.ci.KeyValue;
public class MyUtilsDemo {
public static void main(String[] args) {
// K = Integer: Phone
// V = String: Name
KeyValue<Integer, String> entry1 = new KeyValue<Integer, String>(12000111, "Tom");
KeyValue<Integer, String> entry2 = new KeyValue<Integer, String>(12000112, "Jerry");
// (K = Integer).
Integer phone = MyUtils.getKey(entry1);
System.out.println("Phone = " + phone);
// Une liste contient les éléments de type KeyValue<Integer,String>.
ArrayList<KeyValue<Integer, String>> list = new ArrayList<KeyValue<Integer, String>>();
// Ajouter l'élément à la liste.
list.add(entry1);
list.add(entry2);
KeyValue<Integer, String> firstEntry = MyUtils.getFirstElement(list);
System.out.println("Value = " + firstEntry.getValue());
}
}
4. Initialisation d'objet Generic
Parfois, vous voulez initialiser un objet Généric :
// Créer un objet Generic.
T t = new T(); // Error
L'initialisation d'un objet générique comme au-dessus n'est pas autorisée, car <T> n'existe pas au moment d'exécution de Java. C'est-à-dire simplement avec le compileur de contrôle du code des programmateurs. Tous les types <T> sont les mêmes, il est compris comme Objet lors de l'exécution de Java.
Si vous voulez initialiser l'objet Generic, vous devez fournir au Java un object Class<T> qui permet à Java de créer un objet généric lors de l'exécution en Java Reflection.
Si vous voulez initialiser l'objet Generic, vous devez fournir au Java un object Class<T> qui permet à Java de créer un objet généric lors de l'exécution en Java Reflection.
Bar.java
package org.o7planning.tutorial.generics.o;
import java.util.Date;
public class Bar {
// Cette classe doit avoir un Constructor par défaut.
public Bar() {
}
public void currentDate() {
System.out.println("Now is: " + new Date());
}
}
MyGeneric.java
package org.o7planning.tutorial.generics.o;
public class MyGeneric<T> {
private T tobject;
public MyGeneric(Class<T> tclass)
throws InstantiationException, IllegalAccessException {
this.tobject = (T) tclass.newInstance();
}
public T getTObject() {
return this.tobject;
}
}
MyGenericDemo.java
package org.o7planning.tutorial.generics.o;
public class MyGenericDemo {
public static void main(String[] args) throws Exception {
MyGeneric<Bar> mg = new MyGeneric<Bar>(Bar.class);
Bar bar = mg.getTObject();
bar.currentDate();
}
}
5. Tableau Generic
Vous pouvez déclarer un tableau générique, mais vous ne pouvez pas initialiser un tableau générique.
// Vous pouvez déclarer un tableau generic.
T[] myarray;
// Mais vous ne pouvez pas initialiser un tableau generic.
// (Ceci n'est pas autorisé).
T[] myarray = new T[5]; // Error!
Exemple :
GenericArray.java
package org.o7planning.tutorial.generics.a;
public class GenericArray<T> {
private T[] array;
// Contructor.
public GenericArray(T[] array) {
this.array = array;
}
public T[] getArray() {
return array;
}
// Renvoyer le dernier élément du tableau.
public T getLastElement() {
if (this.array == null || this.array.length == 0) {
return null;
}
return this.array[this.array.length - 1];
}
}
GenericArrayDemo.java
package org.o7planning.tutorial.generics.a;
public class GenericArrayDemo {
public static void main(String[] args) {
// Un tableau des String.
String[] names = new String[] { "Tom", "Jerry" };
GenericArray<String> gArray = new GenericArray<String>(names);
String last = gArray.getLastElement();
System.out.println("Last Element = " + last);
}
}
Revenir à la question de pourquoi Java ne soutient pas d'initialiser un tableau Generic :
// Pourquoi Java ne soutient pas d'initialiser le tableau de Generic?
T[] genericArray = new T[10]; // Error!
La raison est que le type générique n'existe pas au moment de l'exécution. Liste <Chaîne> ou Liste <Entier> sont Liste. Générique ne fonctionne qu'avec dees compilateurs pour vérifier le code des programmeurs. Cela signifie que le compilateur de Java doit savoir ce qui est <T> pour compiler le new T [10] ;. Sans savoir qu'il considérera T comme Objet par défaut. Alors :
// Supposons que Java autorise l'initialisation d'un tableau Generic :
T[] tarray = new T[10];
// Au moment de la compilation (Compile-time)
// le compilateur considérera <T> comme Object.
// La commande au-dessus est équivalente à :
T[] tarray = new Object[10];
// Si au moment de l'exécution de l'application, vous spécifiez <T> comme chaîne.
// Ceci signifie :
String[] tarray = new Object[10];
// Ce qui précédant n'est pas autorisé. La raison :
// Type mismatch: ne convertit de Object[] to String[]
Si vous souhaitez initialiser un tableau générique, vous devez passer l'objet Class <T> à Java qui permet à Java de créer un tableau générique au moment de l'exécution en utilisant Java Reflection. Voyez des exemples illustrés :
GArray.java
package org.o7planning.tutorial.generics.a;
import java.lang.reflect.Array;
public class GArray<T> {
private Class<T> tclass;
private T[] myArray;
public GArray(Class<T> tclass) {
this.tclass = tclass;
final int size = 10;
myArray = (T[]) Array.newInstance(tclass, size);
}
public T[] getMyArray() {
return this.myArray;
}
}
GArrayDemo.java
package org.o7planning.tutorial.generics.a;
public class GArrayDemo {
public static void main(String[] args) {
GArray<Integer> garray = new GArray<Integer>(Integer.class);
Integer[] myArray = garray.getMyArray();
myArray[0] = 1;
myArray[2] = 0;
}
}
6. Generics avec Wildcards
Dans le code générique, le point d'interrogation (?), appelé un représentant (wildcard), il représente un type inconnu. Un type de représentation paramétrique (wildcard parameterized type) est un cas du type Generic, où au moins un type de paramètre est wildcard.
L'exemple de paramètres représentatifs (wildcard parameterized) est :
- Collection<?>
- List<? extends Number>
- Comparator<? super String>
- Pair<String,?>.
Les caractères représentatives peuvent être utilisés dans diverses situations : Comme type de paramètre, de champ ou de variable locale; Parfois comme un type de retour (bien qu'il soit une meilleure pratique de programmation plus spécifique). Le caractère générique n'est jamais utilisé comme argument de type pour une invocation de méthode générique, une création d'instance de classe générique ou un supertype.
Les caractères génériques sont situés dans des positions différentes ont des significations différentes :
- Collection <?> Décrit un ensemble qui accepte tous les types d'arguments (contient tous les types d'objets).
- List<? extends Number> décrit une liste où tous les éléments sont du type Number ou sous-type de Number.
- Comparator<? super String> décrit un comparateur (Comparator) dont le paramètre doit être String ou String parent.
Un type de caractère représentatif n'est pas un type spécifique pour pouvoir apparaître dans un opérateur new. Il est suggéré que les règles appliquées par les génériques java avec lequel des types sont validés dans tous les scénarios particuliers où les caractères représentatifs ont été utilisés.
Exemple:
Collection<?> coll = new ArrayList<String>();
// Un ensemble contient uniquement le type Number ou sous-type de Number
List<? extends Number> list = new ArrayList<Long>();
//
// Un objet possède des paramètres de type représentent.
// (A wildcard parameterized type)
Pair<String,?> pair = new Pair<String,Integer>();
Certaines déclarations sont invalides.
// String n'est pas le sous-type de Number, donc il y a une erreur.
List<? extends Number> list = new ArrayList<String>();
// String n'est pas un type parent d'Integer, donc il y a une erreur.
ArrayList<? super String> cmp = new ArrayList<Integer>();
L'exemple avec le type représentatif (wildcard)
WildCardExample1.java
package org.o7planning.tutorial.generics.w;
import java.util.ArrayList;
public class WildCardExample1 {
public static void main(String[] args) {
// Une liste contient les éléments de type String.
ArrayList<String> listString = new ArrayList<String>();
listString.add("Tom");
listString.add("Jerry");
// Une liste contient les éléments de type Integer
ArrayList<Integer> listInteger = new ArrayList<Integer>();
listInteger.add(100);
// Vous ne pouvez pas déclarer:
ArrayList<Object> list1 = listString; // ==> Error!
// Un objet avec type paramètre représentant
// (wildcard parameterized object).
ArrayList<? extends Object> list2;
// Vous pouvez déclarer:
list2 = listString;
// Ou
list2 = listInteger;
}
}
WildCardExample2.java
package org.o7planning.tutorial.generics.w;
import java.util.ArrayList;
import java.util.List;
public class WildCardExample2 {
public static void printElement(List<?> list) {
for (Object e : list) {
System.out.println(e);
}
}
public static void main(String[] args) {
List<String> names = new ArrayList<String>();
names.add("Tom");
names.add("Jerry");
names.add("Donald");
List<Integer> values = new ArrayList<Integer>();
values.add(100);
values.add(120);
System.out.println("--- Names --");
printElement(names);
System.out.println("-- Values --");
printElement(values);
}
}
L'objet représentatif ne peut pas utiliser la méthode Generic
ValidWildcard1.java
package org.o7planning.tutorial.generics.w;
import java.util.ArrayList;
public class ValidWildcard1 {
public static void main(String[] args) {
// Une liste contient les éléments de type String.
ArrayList<String> listString = new ArrayList<String>();
// Utilisation de la méthode generic: add(E).
// Ajouter un élément différent de null à la liste
listString.add("Tom");
listString.add("Jerry");
// Ajouter un élément null à la liste.
listString.add(null);
}
}
InvalidWildcard1.java
package org.o7planning.tutorial.generics.w;
import java.util.ArrayList;
public class InvalidWildcard1 {
public static void main(String[] args) {
// Une liste avec le type du paramètre représentant
// (wildcard parameterized type).
ArrayList<? extends Object> listWildcard = listString;
// Vous ne pouvez pas utiliser la méthode add(E)
// avec les paramètres qui ont la valeur différente null
listWildcard.add("Tom"); // ==> Error!
listWildcard.add("Jerry"); // ==> Error!
// Ajouter un élément null à la liste.
listWildcard.add(null);
}
}
Wildcard ne peut pas participer à l'opérateur new
Un type de paramètre générique (wildcard parameterized type) n'est pas un type spécifique et il ne peut pas apparaître dans un opérateur new.
// Paramètre Wildcard ne peut pas participer à l'opérateur new
List<? extends Object> list= new ArrayList<? extends Object>();
Java Basic
- Personnaliser le compilateur Java pour traiter votre annotation (Annotation Processing Tool)
- Programmation Java pour l'équipe utilisant Eclipse et SVN
- Le Tutoriel de Java WeakReference
- Le Tutoriel de Java PhantomReference
- Tutoriel sur la compression et la décompression Java
- Configuration d'Eclipse pour utiliser le JDK au lieu de JRE
- Méthodes Java String.format() et printf()
- Syntaxe et nouvelles fonctionnalités de Java 8
- Expression régulière en Java
- Tutoriel de programmation Java multithreading
- Bibliothèques de pilotes JDBC pour différents types de bases de données en Java
- Tutoriel Java JDBC
- Obtenir des valeurs de colonne automatiquement incrémentées lors de l'insertion d'un enregistrement à l'aide de JDBC
- Le Tutoriel de Java Stream
- Le Tutoriel de Java Functional Interface
- Introduction à Raspberry Pi
- Le Tutoriel de Java Predicate
- Classe abstraite et interface en Java
- Modificateurs d'accès en Java
- Le Tutoriel de Java Enum
- Le Tutoriel de Java Annotation
- Comparer et trier en Java
- Le Tutoriel de Java String, StringBuffer et StringBuilder
- Tutoriel de gestion des exceptions Java
- Le Tutoriel de Java Generics
- Manipulation de fichiers et de répertoires en Java
- Le Tutoriel de Java BiPredicate
- Le Tutoriel de Java Consumer
- Le Tutoriel de Java BiConsumer
- Qu'est-ce qui est nécessaire pour commencer avec Java?
- L'histoire de Java et la différence entre Oracle JDK et OpenJDK
- Installer Java sur Windows
- Installer Java sur Ubuntu
- Installer OpenJDK sur Ubuntu
- Installer Eclipse
- Installer Eclipse sur Ubuntu
- Le Tutoriel Java pour débutant
- Histoire des bits et des bytes en informatique
- Types de données dans Java
- Opérations sur les bits
- Le Tutoriel de instruction Java If else
- Le Tutoriel de instruction Java Switch
- Les Boucles en Java
- Les Tableaux (Array) en Java
- JDK Javadoc au format CHM
- Héritage et polymorphisme en Java
- Le Tutoriel de Java Function
- Le Tutoriel de Java BiFunction
- Exemple de Java encoding et decoding utilisant Apache Base64
- Le Tutoriel de Java Reflection
- Invocation de méthode à distance en Java
- Le Tutoriel de Java Socket
- Quelle plate-forme devez-vous choisir pour développer des applications de bureau Java?
- Le Tutoriel de Java Commons IO
- Le Tutoriel de Java Commons Email
- Le Tutoriel de Java Commons Logging
- Comprendre Java System.identityHashCode, Object.hashCode et Object.equals
- Le Tutoriel de Java SoftReference
- Le Tutoriel de Java Supplier
- Programmation orientée aspect Java avec AspectJ (AOP)
Show More
- Tutoriels de programmation Java Servlet/JSP
- Tutoriels de Java Collections Framework
- Tutoriels Java API pour HTML & XML
- Tutoriels Java IO
- Tutoriels Java Date Time
- Tutoriels Spring Boot
- Tutoriels Maven
- Tutoriels Gradle
- Tutoriels Java Web Service
- Tutoriels de programmation Java SWT
- Tutoriels de JavaFX
- Tutoriels Java Oracle ADF
- Tutoriels Struts2
- Tutoriels Spring Cloud