uso objeto instanciar genericos genericas generica comparar clases arreglos java templates class generics

objeto - ¿Cómo usar la Clase<T> en Java?



list generica java (10)

A menudo desea utilizar comodines con Class . Por ejemplo, Class<? extends JComponent> Class<? extends JComponent> , le permitiría especificar que la clase es alguna subclase de JComponent . Si ha recuperado la instancia de Class de Class.forName , entonces puede usar Class.asSubclass para hacer la Class.asSubclass antes de intentar, por ejemplo, construir una instancia.

Hay una buena discusión sobre los genéricos y lo que realmente hacen entre bambalinas en esta pregunta , por lo que todos sabemos que Vector<int[]> es un vector de matrices de enteros, y HashTable<String, Person> es una tabla de cuyas claves Son cuerdas y valores de la Person . Sin embargo, lo que me impresiona es el uso de la Class<> .

Se supone que la Class clase java también debe tomar un nombre de plantilla, (o eso me dice el subrayado amarillo en eclipse). No entiendo lo que debería poner allí. El punto completo del objeto Class es cuando no tiene la información completa acerca de un objeto, para la reflexión y tal. ¿Por qué me hace especificar qué clase mantendrá el objeto de Class ? Claramente no lo sé, o no estaría usando el objeto Class , usaría el específico.


Como señalan otras respuestas, hay muchas y buenas razones por las que esta class se hizo genérica. Sin embargo, hay muchas veces que no tiene forma de saber el tipo genérico para usar con la Class<T> . En estos casos, simplemente puede ignorar las advertencias del eclipse amarillo o puede usar la Class<?> ... Así es como lo hago;)


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 tiempo de ejecución y de tipo de compilación. Esto permite un estilo de fábricas estáticas ejemplificado por el método getAnnotation en la nueva interfaz AnnotatedElement:

<T extends Annotation> T getAnnotation(Class<T> annotationType);

Este es un método genérico. Infiere el valor de su parámetro de tipo T a partir de su argumento y devuelve una instancia apropiada de T, como se ilustra en el siguiente fragmento de código:

Author a = Othello.class.getAnnotation(Author.class);

Antes de los genéricos, habría tenido que enviar el resultado al Autor. Además, no habría tenido ninguna manera de hacer que el compilador compruebe que el parámetro real representa una subclase de Anotación. [...]

Bueno, nunca tuve que usar este tipo de cosas. ¿Nadie?


El uso de la versión generada de la clase Clase le permite, entre otras cosas, escribir cosas como

Class<? extends Collection> someCollectionClass = someMethod();

y luego puede estar seguro de que el objeto Clase que recibe amplía la Collection , y una instancia de esta clase será (al menos) una Colección.


Es confuso al principio. Pero ayuda en las siguientes situaciones:

class SomeAction implements Action { } // Later in the code. Class<Action> actionClass = Class.forName("SomeAction"); Action action = actionClass.newInstance(); // Notice you get an Action instance, there was no need to cast.


He encontrado la class<T> útil cuando creo búsquedas de registro de servicio. P.ej

<T> T getService(Class<T> serviceClass) { ... }


Siguiendo la respuesta de @Kire Haglin, se puede ver un ejemplo adicional de métodos genéricos en la documentación de JAXB :

public <T> T unmarshal( Class<T> docClass, InputStream inputStream ) throws JAXBException { String packageName = docClass.getPackage().getName(); JAXBContext jc = JAXBContext.newInstance( packageName ); Unmarshaller u = jc.createUnmarshaller(); JAXBElement<T> doc = (JAXBElement<T>)u.unmarshal( inputStream ); return doc.getValue(); }

Esto permite que unmarshal devuelva un documento de un tipo de árbol de contenido JAXB arbitrario.


Solo para agregar otro ejemplo, la versión genérica de Clase ( Class<T> ) permite escribir funciones genéricas como la que se muestra a continuación.

public static <T extends Enum<T>>Optional<T> optionalFromString( @NotNull Class<T> clazz, String name ) { return Optional<T> opt = Optional.ofNullable(name) .map(String::trim) .filter(StringUtils::isNotBlank) .map(String::toUpperCase) .flatMap(n -> { try { return Optional.of(Enum.valueOf(clazz, n)); } catch (Exception e) { return Optional.empty(); } }); }


Solo usa la clase de carne de res:

public <T> T beefmarshal( Class<beef> beefClass, InputBeef inputBeef ) throws JAXBException { String packageName = docClass.getPackage().getBeef(); JAXBContext beef = JAXBContext.newInstance( packageName ); Unmarshaller u = beef.createBeef(); JAXBElement<T> doc = (JAXBElement<T>)u.beefmarshal( inputBeef ); return doc.getBeef(); }


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

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 con Teacher.class

Esto puede evitarse 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. Posteriormente esa T será sustituida por
Nombre de clase válido durante la inicialización ( HashMap<String> map = new HashMap<String>(); )

por ejemplo) class name<T1, T2, ..., Tn>

Entonces, la Class<T> representa un objeto de clase del tipo de clase específico '' T ''.

Supongamos que sus métodos de clase tienen que trabajar con parámetros de tipo desconocido 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 se puede usar como tipo de String como CarName

O T se puede usar como tipo Integer como número de modelo ,

O T se puede utilizar como tipo de Object como instancia de automóvil válida .

Ahora aquí lo anterior es el simple POJO que se puede usar de manera diferente en el tiempo de ejecución.
Las colecciones, por ejemplo, List, Set, Hashmap, son los mejores ejemplos que funcionarán con diferentes objetos según la declaración de T, pero una vez que declaramos T como String
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, dentro de paréntesis angulares, y aparece antes del tipo de retorno del método. Para los métodos genéricos, la sección de parámetros 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> es la declaración de los tipos utilizados en los argumentos del método que deben ir antes del tipo de retorno que es boolean aquí.

En el siguiente; La declaración de tipo <T> no es necesaria en el nivel de método, ya que ya está declarada en el nivel de clase.

class MyClass<T> { private T myMethod(T a){ return a; } }

Pero a continuación está mal, 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 declaración <T> 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.

También lea Restricciones en Genéricos