Todo lo que sabemos es " Todas las instancias de cualquier clase comparten el mismo objeto java.lang.Class de ese tipo de clase "
p.ej)
Student a = new Student();
Student b = new Student();
Entonces a.getClass() == b.getClass()
es verdad.
Ahora asume
Teacher t = new Teacher();
sin genéricos lo siguiente es posible.
Class studentClassRef = t.getClass();
Pero esto está mal ahora ...?
por ejemplo) public void printStudentClassInfo(Class studentClassRef) {}
se puede llamar conTeacher.class
Esto se puede evitar usando genéricos.
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Ahora que es T ?? T es parámetros de tipo (también llamados variables de tipo); delimitado por corchetes angulares (<>), sigue el nombre de la clase.
T es solo un símbolo, como un nombre de variable (puede ser cualquier nombre) declarado durante la escritura del archivo de clase. Más tarde, T será sustituido con
un nombre de clase válido durante la inicialización ( HashMap<String> map = new HashMap<String>();
)
p.ej) class name<T1, T2, ..., Tn>
Por lo tanto, Class<T>
representa un objeto de clase de tipo de clase específico ' T
'.
Suponga que sus métodos de clase tienen que funcionar con parámetros de tipo desconocidos como a continuación
/**
* 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; }
}
Aquí T puede usarse como String
tipo como CarName
O T puede usarse como Integer
tipo como modelNumber ,
O T puede usarse como Object
tipo como instancia de automóvil válida .
Ahora aquí lo anterior es el POJO simple que se puede usar de manera diferente en tiempo de ejecución.
Colecciones, por ejemplo) Lista, Conjunto, Mapa de hash son los mejores ejemplos que funcionarán con diferentes objetos según la declaración de T, pero una vez que declaramos T como Cadena,
por ejemplo) HashMap<String> map = new HashMap<String>();
Entonces solo aceptará objetos de instancia de Clase de cadena.
Métodos genéricos
Los métodos genéricos son métodos que introducen sus propios parámetros de tipo. Esto es similar a declarar un tipo genérico, pero el alcance del parámetro de tipo se limita al método donde se declara. Se permiten métodos genéricos estáticos y no estáticos, así como constructores de clases genéricos.
La sintaxis de un método genérico incluye un parámetro de tipo, entre corchetes angulares y aparece antes del tipo de retorno del método. Para los métodos genéricos, la sección del parámetro de tipo debe aparecer antes del tipo de retorno del método.
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;
}
Aquí <K, V, Z, Y>
está la declaración de los tipos utilizados en los argumentos del método que deberían antes del tipo de retorno que está boolean
aquí.
En el de abajo; La declaración de tipo <T>
no se requiere a nivel de método, ya que ya se ha declarado a nivel de clase.
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
Pero a continuación es incorrecto ya que los parámetros de tipo de nivel de clase K, V, Z e Y no se pueden usar en un contexto estático (método estático aquí).
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());
}
}
OTROS ESCENARIOS VÁLIDOS SON
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;
}
}
Y finalmente, el método estático siempre necesita una <T>
declaración explícita ; No se derivará del nivel de clase Class<T>
. Esto se debe a que el nivel de clase T está vinculado con la instancia.
Lea también Restricciones sobre genéricos
Comodines y subtipos
argumento de tipo para un método genérico