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
De la documentación de Java:
[...] Más sorprendentemente, la clase Clase ha sido generada. Los literales de clase ahora funcionan como tokens de tipo, proporcionando información de tipo tanto en tiempo de ejecución como en tiempo de compilación. Esto permite un estilo de fábricas estáticas ejemplificadas por el método getAnnotation en la nueva interfaz AnnotatedElement:
Este es un método genérico. Infiere el valor de su parámetro de tipo T de su argumento y devuelve una instancia apropiada de T, como se ilustra en el siguiente fragmento:
Antes de los genéricos, habría tenido que enviar el resultado al autor. Además, no habría tenido forma de hacer que el compilador verifique que el parámetro real representara una subclase de Anotación. [...]
Bueno, nunca tuve que usar este tipo de cosas. ¿Nadie?
fuente
Class<? extends X>
notación, pensé que podría limitarla solo a los tipos de 'servicio'. Excepto que no había un tipo de 'servicio' común, por lo que solo podía hacerloClass<?>
. Pobre de mí.He encontrado
class<T>
útil cuando creo búsquedas de registro de servicio. P.ejfuente
Como señalan otras respuestas, hay muchas y buenas razones por las cuales esto
class
se hizo genérico. Sin embargo, hay muchas veces que no tienes forma de conocer el tipo genérico con el que usarClass<T>
. En estos casos, simplemente puede ignorar las advertencias de eclipse amarillo o puede usarClass<?>
... Así es como lo hago;)fuente
@SuppressWarnings("unchecked")
viene al rescate! (Sólo tenga cuidado de aplicar siempre que se alcance como una pequeña como sea posible, ya que hace posibles problemas oscuros en su código.)Siguiendo la respuesta de @Kire Haglin, se puede ver un ejemplo adicional de métodos genéricos en la documentación para la desagregación de JAXB :
Esto permite
unmarshal
devolver un documento de un tipo arbitrario de árbol de contenido JAXB.fuente
A menudo quieres usar comodines con
Class
. Por ejemplo,Class<? extends JComponent>
le permitiría especificar que la clase es alguna subclase deJComponent
. Si ha recuperado laClass
instancia deClass.forName
, entonces puede usarClass.asSubclass
para hacer el lanzamiento antes de intentar, por ejemplo, construir una instancia.fuente
En java
<T>
significa clase genérica. Una clase genérica es una clase que puede funcionar en cualquier tipo de tipo de datos o, en otras palabras, podemos decir que es independiente del tipo de datos.Donde T significa tipo. Ahora, cuando cree una instancia de esta clase Shape, deberá decirle al compilador en qué tipo de datos estará trabajando.
Ejemplo:
Integer es un tipo y String también es un tipo.
<T>
específicamente significa tipo genérico. Según Java Docs: un tipo genérico es una clase o interfaz genérica que se parametriza sobre tipos.fuente
Solo para agregar otro ejemplo, la versión genérica de Class (
Class<T>
) le permite a uno escribir funciones genéricas como la siguiente.fuente
Es confuso al principio. Pero ayuda en las siguientes situaciones:
fuente
Action a = new Action()
?Action
i una interfaz,SomeAction
estamos tratando de obtener una instancia de. Solo tenemos el nombre deSomeAction
disponible en tiempo de ejecución.Solo usa la clase de carne de res:
fuente