tutorial que interfaz grafica español ejemplos contenedores componentes java generics reflection

que - java swing tutorial pdf español



Obtener el tipo de parámetro genérico en Java con reflejo (16)

¿Es posible obtener el tipo de un parámetro genérico?

Un ejemplo:

public final class Voodoo { public static void chill(List<?> aListWithTypeSpiderMan) { // Here I''d like to get the Class-Object ''SpiderMan'' Class typeOfTheList = ???; } public static void main(String... args) { chill(new ArrayList<SpiderMan>()); } }


Apéndice a la respuesta de @ DerMike para obtener el parámetro genérico de una interfaz parametrizada (utilizando el método #getGenericInterfaces () dentro de un método predeterminado Java-8 para evitar la duplicación):

import java.lang.reflect.ParameterizedType; public class ParametrizedStuff { @SuppressWarnings("unchecked") interface Awesomable<T> { default Class<T> parameterizedType() { return (Class<T>) ((ParameterizedType) this.getClass().getGenericInterfaces()[0]) .getActualTypeArguments()[0]; } } static class Beer {}; static class EstrellaGalicia implements Awesomable<Beer> {}; public static void main(String[] args) { System.out.println("Type is: " + new EstrellaGalicia().parameterizedType()); // --> Type is: ParameterizedStuff$Beer }


Como señaló @bertolami, no nos es posible obtener un tipo de variable y obtener su valor futuro (el contenido de la variable typeOfList).

Sin embargo, puede pasar la clase como parámetro de esta manera:

public final class voodoo { public static void chill(List<T> aListWithTypeSpiderMan, Class<T> clazz) { // Here I''d like to get the Class-Object ''SpiderMan'' Class typeOfTheList = clazz; } public static void main(String... args) { chill(new List<SpiderMan>(), Spiderman.class ); } }

Eso es más o menos lo que hace Google cuando tiene que pasar una variable de clase al constructor de ActivityInstrumentationTestCase2 .


Debido a la eliminación del tipo, la única forma de saber el tipo de la lista sería pasar el tipo como un parámetro al método:

public class Main { public static void main(String[] args) { doStuff(new LinkedList<String>(), String.class); } public static <E> void doStuff(List<E> list, Class<E> clazz) { } }


En realidad, hay una solución, aplicando el truco de la "clase anónima" y las ideas de los Super Type Tokens :

public final class Voodoo { public static void chill(final List<?> aListWithSomeType) { // Here I''d like to get the Class-Object ''SpiderMan'' System.out.println(aListWithSomeType.getClass().getGenericSuperclass()); System.out.println(((ParameterizedType) aListWithSomeType .getClass() .getGenericSuperclass()).getActualTypeArguments()[0]); } public static void main(String... args) { chill(new ArrayList<SpiderMan>() {}); } } class SpiderMan { }

El truco está en la creación de una clase anónima , new ArrayList<SpiderMan>() {} , en lugar de la new ArrayList<SpiderMan>() original (simple) new ArrayList<SpiderMan>() . El uso de una clase anónima (si es posible) asegura que el compilador retiene información sobre el argumento tipo SpiderMan dado al parámetro de tipo List<?> . Voilà!


En realidad, tengo esto para trabajar. Considere el siguiente fragmento:

Method m; Type[] genericParameterTypes = m.getGenericParameterTypes(); for (int i = 0; i < genericParameterTypes.length; i++) { if( genericParameterTypes[i] instanceof ParameterizedType ) { Type[] parameters = ((ParameterizedType)genericParameterTypes[i]).getActualTypeArguments(); //parameters[0] contains java.lang.String for method like "method(List<String> value)" } }

Estoy usando jdk 1.6


Esto es imposible porque los genéricos en Java solo se consideran en tiempo de compilación. Por lo tanto, los genéricos de Java son solo una especie de preprocesador. Sin embargo, puede obtener la clase real de los miembros de la lista.


He codificado esto para los métodos que esperan aceptar o devolver Iterable<?...> . Aquí está el código:

/** * Assuming the given method returns or takes an Iterable<T>, this determines the type T. * T may or may not extend WindupVertexFrame. */ private static Class typeOfIterable(Method method, boolean setter) { Type type; if (setter) { Type[] types = method.getGenericParameterTypes(); // The first parameter to the method expected to be Iterable<...> . if (types.length == 0) throw new IllegalArgumentException("Given method has 0 params: " + method); type = types[0]; } else { type = method.getGenericReturnType(); } // Now get the parametrized type of the generic. if (!(type instanceof ParameterizedType)) throw new IllegalArgumentException("Given method''s 1st param type is not parametrized generic: " + method); ParameterizedType pType = (ParameterizedType) type; final Type[] actualArgs = pType.getActualTypeArguments(); if (actualArgs.length == 0) throw new IllegalArgumentException("Given method''s 1st param type is not parametrized generic: " + method); Type t = actualArgs[0]; if (t instanceof Class) return (Class<?>) t; if (t instanceof TypeVariable){ TypeVariable tv = (TypeVariable) actualArgs[0]; AnnotatedType[] annotatedBounds = tv.getAnnotatedBounds();/// GenericDeclaration genericDeclaration = tv.getGenericDeclaration();/// return (Class) tv.getAnnotatedBounds()[0].getType(); } throw new IllegalArgumentException("Unknown kind of type: " + t.getTypeName()); }


La respuesta rápida es que la Pregunta es no, no se puede, debido a la supresión del tipo genérico de Java.

La respuesta más larga sería que si ha creado su lista de esta manera:

new ArrayList<SpideMan>(){}

Entonces, en este caso, el tipo genérico se conserva en la superclase genérica de la nueva clase anónima anterior.

No es que recomiende hacer esto con listas, pero es una implementación de oyente:

new Listener<Type>() { public void doSomething(Type t){...}}

Y como la extrapolación de los tipos genéricos de superclases y súper interfaces cambia entre las JVM, la solución genérica no es tan directa como pueden sugerir algunas respuestas.

Aquí es ahora lo hice.


No puede obtener un parámetro genérico de una variable. Pero puede hacerlo desde un método o declaración de campo:

Method method = getClass().getDeclaredMethod("chill", List.class); Type[] params = method.getGenericParameterTypes(); ParameterizedType firstParam = (ParameterizedType) params[0]; Type[] paramsOfFirstGeneric = firstParam.getActualTypeArguments();


No, eso no es posible. Debido a problemas de compatibilidad con versiones anteriores, los genéricos de Java se basan en el borrado de tipos , es decir, en tiempo de ejecución, todo lo que tiene es un objeto de List no genérico. Existe información sobre los parámetros de tipo en el tiempo de ejecución, pero reside en las definiciones de clase (es decir, puede preguntarse " ¿qué tipo genérico utiliza la definición de este campo? "), No en instancias de objetos.


No, no es posible

Puedes obtener un tipo genérico de un campo dado que una clase es la única excepción a esa regla e incluso eso es un poco complicado.

Consulte Conocer el tipo de genérico en Java para ver un ejemplo de eso.


Puede obtener el tipo de parámetro genérico con reflejo como en este ejemplo que encontré here :

import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; public class Home<E> { @SuppressWarnings ("unchecked") public Class<E> getTypeParameterClass(){ Type type = getClass().getGenericSuperclass(); ParameterizedType paramType = (ParameterizedType) type; return (Class<E>) paramType.getActualTypeArguments()[0]; } private static class StringHome extends Home<String>{} private static class StringBuilderHome extends Home<StringBuilder>{} private static class StringBufferHome extends Home<StringBuffer>{} /** * This prints "String", "StringBuilder" and "StringBuffer" */ public static void main(String[] args) throws InstantiationException, IllegalAccessException { Object object0 = new StringHome().getTypeParameterClass().newInstance(); Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance(); Object object2 = new StringBufferHome().getTypeParameterClass().newInstance(); System.out.println(object0.getClass().getSimpleName()); System.out.println(object1.getClass().getSimpleName()); System.out.println(object2.getClass().getSimpleName()); } }


Quiero tratar de desglosar la respuesta de @DerMike para explicar:

En primer lugar, el tipo de borrado no significa que el JDK elimine la información de tipo en el tiempo de ejecución. Es un método para permitir que la verificación de tipos en tiempo de compilación y la compatibilidad del tipo de tiempo de ejecución coexistan en el mismo idioma. Como este bloque de código lo implica, el JDK conserva la información del tipo borrado, simplemente no está asociado con moldes verificados y demás.

Segundo, esto proporciona información de tipo genérico a una clase genérica exactamente un nivel arriba de la jerarquía del tipo concreto que se comprueba, es decir, una clase padre abstracta con parámetros genéricos puede encontrar los tipos concretos correspondientes a sus parámetros de tipo para una implementación concreta de sí mismo que hereda directamente de él. Si esta clase no fuera abstracta e instanciada, o la implementación concreta estuviera dos niveles inactivos, esto no funcionaría (aunque un poco de engaño podría hacer que se aplicara a cualquier número predeterminado de niveles más allá de uno, o hasta la clase más baja con X parámetros de tipo genérico, etcétera).

De todos modos, a la explicación. Aquí está el código nuevamente, separado en líneas para una fácil referencia:

1# Class genericParameter0OfThisClass = 2# (Class) 3# ((ParameterizedType) 4# getClass() 5# .getGenericSuperclass()) 6# .getActualTypeArguments()[0];

Deje que ''nosotros'' sea la clase abstracta con tipos genéricos que contiene este código. Leyendo esto aproximadamente al revés:

  • La línea 4 obtiene la clase concreta ''Clase instancia. Esto identifica el tipo concreto de nuestro descendiente inmediato.
  • La línea 5 obtiene ese supertipo de clase como Tipo; somos nosotros. Como somos un tipo paramétrico, podemos lanzarnos de manera segura a ParameterizedType (línea 3). La clave es que cuando Java determina este objeto Type, usa información de tipo presente en el elemento secundario para asociar información de tipo con nuestros parámetros de tipo en la nueva instancia ParameterizedType. Entonces ahora podemos acceder a tipos concretos para nuestros genéricos.
  • La línea 6 obtiene la matriz de tipos mapeados en nuestros genéricos, en el orden declarado en el código de clase. Para este ejemplo, sacamos el primer parámetro. Esto vuelve como un tipo.
  • La línea 2 arroja el tipo final devuelto a una clase. Esto es seguro porque sabemos qué tipos pueden tomar nuestros parámetros de tipo genérico y podemos confirmar que todos serán clases (no estoy seguro de cómo en Java se obtendría un parámetro genérico que no tiene una instancia de Clase) asociado con ella, en realidad).

... y eso es más o menos. Por lo tanto, volvemos a insertar información de tipo de nuestra propia implementación concreta en nosotros mismos y la utilizamos para acceder a un manejador de clase. podríamos doblar getGenericSuperclass () e ir dos niveles, o eliminar getGenericSuperclass () y obtener valores para nosotros mismos como un tipo concreto (advertencia: no he probado estos escenarios, aún no han aparecido para mí).

Se vuelve complicado si tus niños concretos están a un número arbitrario de saltos, o si eres concreto y no final, y especialmente complicado si esperas que alguno de tus hijos (variablemente profundos) tenga sus propios genéricos. Pero por lo general, puede diseñar en torno a esas consideraciones, por lo que esto lo lleva la mayor parte del camino.

Espero que esto haya ayudado a alguien! Reconozco que esta publicación es antigua. Probablemente voy a cortar esta explicación y guardarla para otras preguntas.


Solo para mí leer este fragmento de código fue difícil, solo lo dividí en 2 líneas legibles:

// assuming that the Generic Type parameter is of type "T" ParameterizedType p = (ParameterizedType) getClass().getGenericSuperclass(); Class<T> c =(Class<T>)p.getActualTypeArguments()[0];

Quería crear una instancia del parámetro Tipo sin tener ningún parámetro para mi método:

publc T getNewTypeInstance(){ ParameterizedType p = (ParameterizedType) getClass().getGenericSuperclass(); Class<T> c =(Class<T>)p.getActualTypeArguments()[0]; // for me i wanted to get the type to create an instance // from the no-args default constructor T t = null; try{ t = c.newInstance(); }catch(Exception e){ // no default constructor available } return t; }


Una construcción, me encontré con una vez parecía

Class<T> persistentClass = (Class<T>) ((ParameterizedType)getClass().getGenericSuperclass()) .getActualTypeArguments()[0];

Entonces parece que hay algo de magia de reflexión alrededor que desafortunadamente no entiendo completamente ... Lo siento.


Utilizar:

Class<?> typeOfTheList = aListWithTypeSpiderMan.toArray().getClass().getComponentType();