Obtener el tipo genérico de java.útil.Lista


Tengo;

List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();

¿Hay una manera (fácil) de recuperar el tipo genérico de la lista?

 215
Author: skaffman, 2009-12-22

14 answers

Si esos son realmente campos de una determinada clase, entonces puedes obtenerlos con un poco de ayuda de reflexión:

package test;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

public class Test {

    List<String> stringList = new ArrayList<String>();
    List<Integer> integerList = new ArrayList<Integer>();

    public static void main(String... args) throws Exception {
        Field stringListField = Test.class.getDeclaredField("stringList");
        ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
        Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
        System.out.println(stringListClass); // class java.lang.String.

        Field integerListField = Test.class.getDeclaredField("integerList");
        ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType();
        Class<?> integerListClass = (Class<?>) integerListType.getActualTypeArguments()[0];
        System.out.println(integerListClass); // class java.lang.Integer.
    }
}

También puede hacer eso para tipos de parámetros y tipos de métodos de retorno.

Pero si están dentro del mismo alcance de la clase/método donde necesitas saber sobre ellos, entonces no tiene sentido conocerlos, porque ya los has declarado tú mismo.

 340
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-31 21:45:23

También puede hacer lo mismo para los parámetros del método:

Type[] types = method.getGenericParameterTypes();
//Now assuming that the first parameter to the method is of type List<Integer>
ParameterizedType pType = (ParameterizedType) types[0];
Class<?> clazz = (Class<?>) pType.getActualTypeArguments()[0];
System.out.println(clazz); //prints out java.lang.Integer
 17
Author: tsaixingwei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-27 14:11:17

Respuesta corta: no.

Esto es probablemente un duplicado, no se puede encontrar uno apropiado en este momento.

Java usa algo llamado type erasure, lo que significa que en tiempo de ejecución ambos objetos son equivalentes. El compilador sabe que las listas contienen enteros o cadenas, y como tal puede mantener un entorno seguro de tipos. Esta información se pierde (en base a una instancia de objeto) en tiempo de ejecución, y la lista solo contiene 'Objetos'.

Puede averiguar un poco sobre la clase, qué tipos podría ser parametrizado por, pero normalmente esto es cualquier cosa que se extiende "Objeto", es decir, cualquier cosa. Si define un tipo como

class <A extends MyClass> AClass {....}

AClass.class solo contendrá el hecho de que el parámetro A está limitado por MyClass, pero más que eso, no hay forma de saberlo.

 16
Author: falstro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-21 21:15:58

Si necesita obtener el tipo genérico de un tipo devuelto, utilicé este enfoque cuando necesitaba encontrar métodos en una clase que devolviera un Collection y luego acceder a sus tipos genéricos:

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;

public class Test {

    public List<String> test() {
        return null;
    }

    public static void main(String[] args) throws Exception {

        for (Method method : Test.class.getMethods()) {
            Class returnClass = method.getReturnType();
            if (Collection.class.isAssignableFrom(returnClass)) {
                Type returnType = method.getGenericReturnType();
                if (returnType instanceof ParameterizedType) {
                    ParameterizedType paramType = (ParameterizedType) returnType;
                    Type[] argTypes = paramType.getActualTypeArguments();
                    if (argTypes.length > 0) {
                        System.out.println("Generic type is " + argTypes[0]);
                    }
                }
            }
        }

    }

}

Esto produce:

El tipo genérico es la clase java.lang.String

 9
Author: Aram Kocharyan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-29 12:07:53

El tipo genérico de una colección solo debe importar si realmente tiene objetos en ella, ¿verdad? Así que no es más fácil simplemente hacer:

Collection<?> myCollection = getUnknownCollectionFromSomewhere();
Class genericClass = null;
Iterator it = myCollection.iterator();
if (it.hasNext()){
    genericClass = it.next().getClass();
}
if (genericClass != null) { //do whatever we needed to know the type for

No hay tal cosa como un tipo genérico en tiempo de ejecución, pero los objetos dentro en tiempo de ejecución están garantizados para ser el mismo tipo que el genérico declarado, por lo que es bastante fácil probar la clase del elemento antes de procesarlo.

 7
Author: Steve K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-06 06:06:01

Para encontrar el tipo genérico de un campo:

((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()
 7
Author: Mohsen Kashi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-18 14:42:18

Ampliando la respuesta de Steve K:

/** 
* Performs a forced cast.  
* Returns null if the collection type does not match the items in the list.
* @param data The list to cast.
* @param listType The type of list to cast to.
*/
static <T> List<? super T> castListSafe(List<?> data, Class<T> listType){
    List<T> retval = null;
    //This test could be skipped if you trust the callers, but it wouldn't be safe then.
    if(data!=null && !data.isEmpty() && listType.isInstance(data.iterator().next().getClass())) {
        @SuppressWarnings("unchecked")//It's OK, we know List<T> contains the expected type.
        List<T> foo = (List<T>)data;
        return retval;
    }
    return retval;
}
Usage:

protected WhateverClass add(List<?> data) {//For fluant useage
    if(data==null) || data.isEmpty(){
       throw new IllegalArgumentException("add() " + data==null?"null":"empty" 
       + " collection");
    }
    Class<?> colType = data.iterator().next().getClass();//Something
    aMethod(castListSafe(data, colType));
}

aMethod(List<Foo> foo){
   for(Foo foo: List){
      System.out.println(Foo);
   }
}

aMethod(List<Bar> bar){
   for(Bar bar: List){
      System.out.println(Bar);
   }
}
 6
Author: ggb667,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-28 12:42:02

En tiempo de ejecución, no, no puedes.

Sin embargo, mediante reflexión, los parámetros de tipo son accesibles. Try

for(Field field : this.getDeclaredFields()) {
    System.out.println(field.getGenericType())
}

El método getGenericType() devuelve un objeto de Tipo. En este caso, será una instancia de ParametrizedType, que a su vez tiene métodos getRawType() (que contendrá List.class, en este caso) y getActualTypeArguments(), que devolverá un array (en este caso, de longitud uno, conteniendo String.class o Integer.class).

 4
Author: Scott Morrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-21 21:19:45

Generalmente imposible, porque List<String> y List<Integer> comparten la misma clase de tiempo de ejecución.

Sin embargo, es posible que pueda reflejar el tipo declarado del campo que contiene la lista (si el tipo declarado no se refiere a un parámetro de tipo cuyo valor no conoce).

 3
Author: meriton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-21 21:15:30

Como otros han dicho, la única respuesta correcta es no, el tipo ha sido borrado.

Si la lista tiene un número distinto de cero de elementos, podría investigar el tipo del primer elemento ( usando su método getClass, por ejemplo ). Eso no le dirá el tipo genérico de la lista, pero sería razonable asumir que el tipo genérico fue alguna superclase de los tipos en la lista.

No abogaría por el enfoque, pero en un aprieto podría ser útil.

 2
Author: Chris Arguin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-21 21:15:17

Tenía el mismo problema, pero usé instanceof en su lugar. Lo hizo de esta manera:

List<Object> listCheck = (List<Object>)(Object) stringList;
    if (!listCheck.isEmpty()) {
       if (listCheck.get(0) instanceof String) {
           System.out.println("List type is String");
       }
       if (listCheck.get(0) instanceof Integer) {
           System.out.println("List type is Integer");
       }
    }
}

Esto implica el uso de moldes sin marcar, así que solo haga esto cuando sepa que es una lista y de qué tipo puede ser.

 2
Author: Andy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-10 17:49:07
import org.junit.Assert;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class GenericTypeOfCollectionTest {
    public class FormBean {
    }

    public class MyClazz {
        private List<FormBean> list = new ArrayList<FormBean>();
    }

    @Test
    public void testName() throws Exception {
        Field[] fields = MyClazz.class.getFields();
        for (Field field : fields) {
            //1. Check if field is of Collection Type
            if (Collection.class.isAssignableFrom(field.getType())) {
                //2. Get Generic type of your field
                Class fieldGenericType = getFieldGenericType(field);
                //3. Compare with <FromBean>
                Assert.assertTrue("List<FormBean>",
                  FormBean.class.isAssignableFrom(getFieldGenericTypefieldGenericType));
            }
        }
    }

    //Returns generic type of any field
    public Class getFieldGenericType(Field field) {
        if (ParameterizedType.class.isAssignableFrom(field.getGenericType().getClass())) {
            ParameterizedType genericType =
             (ParameterizedType) field.getGenericType();
            return ((Class)
              (genericType.getActualTypeArguments()[0])).getSuperclass();
        }
        //Returns dummy Boolean Class to compare with ValueObject & FormBean
        return new Boolean(false).getClass();
    }
}
 1
Author: Ashish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-25 05:00:34
 0
Author: peter.murray.rust,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-21 21:11:22

Use Reflexión para obtener el Field para estos, entonces puede hacer: field.genericType para obtener el tipo que contiene la información sobre genérico también.

 0
Author: Siddharth Shishulkar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-25 07:13:58