Le Tutoriel de Java Generics

View more categories:

1- Pourquoi Java Generics?

Generics est un concept qui est mis en Java depuis la version 5. Avant de donner la notion de Generics , on voit un fragment 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éez 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 sortez le premier élément
		// C'est un objet (mais vous savez que c'est un String)
		// ==> tom
		Object obj1 = userNames.get(0);

		// Pressé type (cast) au String
		String userName1 = (String) obj1;

		System.out.println("userName1 = " + userName1);

		// Sortez deuxième éléments
		// (vous savez que c'est String)
		// ==> jerry
		String userName2 = (String) userNames.get(1);

		System.out.println("userName2 = " + userName2);

		// Sortez troisième éléments et Pressé 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 quelque part dans le programme que vous ajoutez à cette liste un élément n'est pas String (Ceci est tout à fait possible) lorsque vous sortez de ces éléments et forcez le type de String, une exception sera levée.
  • TODO (Image)
Java 5 mis 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 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éez un ArrayList (Une liste)
		// Cette liste ne permet que contenir l'élément de type String.
		ArrayList<String> userNames = new ArrayList<String>();

		// Ajouter les String à la liste.
		userNames.add("tom");
		userNames.add("jerry");

		// Vous ne pouvez pas ajouter des éléments non-String à la liste.
		// (Erreur lors de la compilation).
		userNames.add(new Integer(100)); // Compile Error!

		// Vous n'avez pas besoin de lancer sur le type (cast) de l'élément.
		String userName1 = userNames.get(0);

		System.out.println("userName1 = " + userName1);

	}

}
Lorsque vous créez un objet ArrayList<String> ne contient que des éléments de type String, le compilateur Java ne permet pas cet objet contient d'autres éléments de type String.

2- Type Generic pour Class & Interface

2.1- 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.

Voyez 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éez un object KeyValue
		// Integer: Numéro de téléphone (K = Integer)
		// String: 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:

2.2- Héritage Classe Generics

Une classe étendue à partir d'une classe générique peut spécifier un type de paramètre pour les génériques, 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 classe KeyValue==<==K,V>.
// Et spécifiez uniquement K,V :
// K = Integer  (Numéro de téléphone).
// V = String   (Nom de l'utilisateu).
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 le type de retour qui est Integer.
		Integer phone = entry.getKey();

		// Java comprend 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écifiez le paramètre de type <K> est String.
// Gardez 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  StringAndValueEntry classe:
StringAndValueEntryDemo.java
package org.o7planning.tutorial.generics.ci;

public class StringAndValueEntryDemo {

	public static void main(String[] args) {

		// (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 <
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;
	}

}

2.3- Generics Interface

Une Interface qui a des paramètres Génériques
GenericInterface.java
package org.o7planning.tutorial.generics.ci;

public interface GenericInterface<G> {

 
  public G doSomething();
 
}
Par exemple, une classe mise en œuvre sur l'interface
GenericInterfaceImpl.java
package org.o7planning.tutorial.generics.ci;

public class GenericInterfaceImpl<G> implements GenericInterface<G>{

   private G something;
   
   @Override
   public G doSomething() {
       return something;
   }

}

2.4- Java n'appuie pas Generic Throwable

Vous ne pouvez pas créer une classe générique qui est descendante de  Throwable , car java ne supporte pas la création de la classe.
Annoncer les erreurs du compilateur:
- The generic class MyException<E> may not subclass java.lang.Throwable
Java ne prend pas en charge 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 que pour le 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> : Dire que cette méthode a deux paramètres K, V
	// La méthode retourne un objet de type K.
	public static <K, V> K getKey(KeyValue<K, V> entry) {
		K key = entry.getKey();
		return key;
	}

	// <K,V> : Dire que cette méthode a deux paramètres K, V
	// La méthode retourne 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 des éléments de type E.
	// La méthode retourne un objet de type E.
	public static <E> E getFirstElement(ArrayList<E> list) {
		if (list == null || list.isEmpty()) {
			return null;
		}
		E first = list.get(0);
		return first;
	}

}
L'exemple utilise 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 des é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érique:
// Initialisation d'objet Generic.
T t = new T(); // Error
L'initialisation d'un objet générique comme ci-dessus ne sont pas autorisés, car n'existe pas au moment d'exécution de Java. Il n'a que le sens avec la compilation de contrôle du code de programmateur. Tous les types tous les mêmes, il est entendu que l' Objet lors de l'exécution de Java.

Vous voulez initialiser l'objet générique vous devez fournir pour Java un object Class<T>, Java va créer un objet<T> 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;
	}

	// Renvoie 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 prend pas en charge une initialisation de tableau générique:
// Pourquoi Java n'appuie pas 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 les compilateurs pour vérifier le code des programmeurs. Cela signifie que le compilateur de Java doit savoir ce qui est <T> pour compiler le nouveau 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 ci-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.
// Signifier:
String[] tarray = new Object[10];

// Ce qui précède n'est pas autorisé. Cause:
// Type mismatch: cannot convert from Object[] to String[]
Si vous souhaitez initialiser un tableau générique, vous devez passer l'objet  Class <T> à Java qui aide Java à créer un tableau générique au moment de l'exécution en utilisant Java Reflection . Voyez l'exemple illustré:
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 (type génériques paramétrés) est un cas du type générique, où au moins un type de paramètre est générique
 Des exemples de paramètres représentatifs (générique paramétré) est:
  • Collection<?>
  • List<? extends Number>
  • Comparator<? super String>
  • Pair<String,?>.
Les caractères génériques 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> mô tả một danh sách, nơi mà các phần tử là kiểu Number ou sous-type de Number.
  • Comparator<? super String>décrire un comparateur (Comparator) dont le paramètre doit être String ou String parent.
Un type de caractère générique n'est pas un type spécifique pour pouvoir apparaître dans un nouvel opérateur. Il est suggéré que les règles appliquées par les génériques java ce genre de valeur dans une situation particulière qui représentent des symboles 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>();
Certains déclarés invalides.
// String n'est pas le sous-type de Number, donc une erreur.
List<? extends Number> list = new ArrayList<String>();  

// String n'est pas un type parent d'Integer, donc une erreur.
ArrayList<? super String> cmp = new ArrayList<Integer>();

6.1- L'exemple avec le type de représentation (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);

   }

}

6.2- L'objet représentant 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>();

		// Utilisez 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);

	}

}

6.3- Wildcard ne peut pas participer à l'opérateur new

Un type de paramètre générique (type génériques paramétrés) n'est pas un type spécifique et il ne peut pas apparaître dans un nouvel opérateur.
// Paramètre Wildcard ne peut pas participer à l'opérateur new
List<? extends Object> list= new ArrayList<? extends Object>();

View more categories: