我有;

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

是否有(简单)方法检索列表的泛型类型?


当前回答

扩展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;
        retval=foo;
    }
    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);
   }
}

其他回答

在运行时,不可以。

但是,通过反射可以访问类型参数。试一试

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

方法getGenericType()返回一个Type对象。在这种情况下,它将是一个paramtrizedtype的实例,它又有方法getRawType()(在这种情况下,它将包含List.class)和getActualTypeArguments(),它将返回一个数组(在这种情况下,长度为1,包含String.class或Integer.class)。

一个小的帮助方法:

/**
 * Get type of collection field.
 *
 * @param aClass A class containing collection.
 * @param collectionName A collection field name.
 */
@SneakyThrows
public static Class<?> getCollectionType(Class<?> aClass, String collectionName) {
  Field field = aClass.getDeclaredField(collectionName);
  ParameterizedType genericType = (ParameterizedType) field.getGenericType();
  return (Class<?>) genericType.getActualTypeArguments()[0];
}

你也可以对方法参数做同样的事情:

Method method = someClass.getDeclaredMethod("someMethod");
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

正如其他人所说,唯一正确的答案是否定的,该类型已被删除。

如果列表的元素数目非零,则可以研究第一个元素的类型(例如,使用它的getClass方法)。这不会告诉您列表的泛型类型,但可以合理地假设泛型类型是列表中类型的某个超类。

我不提倡这种方法,但在遇到困难时,它可能会有用。

我找到了一个非常适合我的答案。

class ArrayListString extends ArrayList<String> {}
class ArrayListInteger extends ArrayList<Integer> {}

ArrayListString als = new ArrayListString();
ArrayListInteger ali = new ArrayListInteger();

void whatType(Object a) {
    if (a instanceof ArrayListString)
        System.out.println("ArrayListString");
    else if (a instanceof ArrayListInteger)
        System.out.println("ArrayListInteger");
}

whatType(als);
whatType(ali);

Als和ali将像它们的泛型一样工作。

这段代码所做的是将泛型类型转换为常规Java类型。在Java中,可以使用instanceof检测常规类型。