Tout ce que nous savons, c'est que « toutes les instances d'une classe quelconque partagent le même objet java.lang.Class de ce type de classe »
par exemple)
Student a = new Student();
Student b = new Student();
ensuite a.getClass() == b.getClass()
c'est vrai.
Supposons maintenant
Teacher t = new Teacher();
sans génériques, ce qui suit est possible.
Class studentClassRef = t.getClass();
Mais c'est faux maintenant ..?
par exemple) public void printStudentClassInfo(Class studentClassRef) {}
peut être appelé avecTeacher.class
Cela peut être évité en utilisant des génériques.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Maintenant, qu'est-ce que T ?? T est des paramètres de type (également appelés variables de type); délimité par des crochets (<>), suit le nom de la classe.
T est juste un symbole, comme un nom de variable (peut être n'importe quel nom) déclaré lors de l'écriture du fichier de classe. Plus tard, T sera remplacé par
un nom de classe valide lors de l'initialisation (HashMap<String> map = new HashMap<String>();
)
par exemple) class name<T1, T2, ..., Tn>
Class<T>
Représente donc un objet de classe de type de classe spécifique 'T
'.
Supposons que vos méthodes de classe doivent fonctionner avec des paramètres de type inconnus comme ci-dessous
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Ici, T peut être utilisé comme String
type CarName
OU T peut être utilisé comme Integer
type comme modelNumber ,
OU T peut être utilisé comme Object
type d' instance de voiture valide .
Maintenant, voici le POJO simple qui peut être utilisé différemment au moment de l'exécution.
Collections, par exemple) List, Set, Hashmap sont les meilleurs exemples qui fonctionneront avec différents objets selon la déclaration de T, mais une fois que nous avons déclaré T comme chaîne,
par exemple)HashMap<String> map = new HashMap<String>();
Ensuite, il n'acceptera que les objets d'instance String Class.
Méthodes génériques
Les méthodes génériques sont des méthodes qui introduisent leurs propres paramètres de type. Cela revient à déclarer un type générique, mais la portée du paramètre type est limitée à la méthode où il est déclaré. Les méthodes génériques statiques et non statiques sont autorisées, ainsi que les constructeurs de classes génériques.
La syntaxe d'une méthode générique inclut un paramètre de type, entre crochets, et apparaît avant le type de retour de la méthode. Pour les méthodes génériques, la section des paramètres de type doit apparaître avant le type de retour de la méthode.
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
Voici <K, V, Z, Y>
la déclaration des types utilisés dans les arguments de méthode qui devraient avant le type de retour qui estboolean
ici.
Dans le ci-dessous; la déclaration de type <T>
n'est pas requise au niveau de la méthode, car elle est déjà déclarée au niveau de la classe.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Mais ci-dessous est faux car les paramètres de type au niveau de la classe K, V, Z et Y ne peuvent pas être utilisés dans un contexte statique (méthode statique ici).
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
D'AUTRES SCÉNARIOS VALIDES SONT
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
// Should be o.myMethod3(String.valueOf("1").getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
Et enfin, la méthode statique a toujours besoin d'une <T>
déclaration explicite ; Il ne dérivera pas du niveau de la classe Class<T>
. Cela est dû au fait que le niveau de classe T est lié à l'instance.
Lisez aussi Restrictions sur les génériques
Caractères génériques et sous-typage
argument de type pour une méthode générique