Get generic type of java.util.List

2018-12-31 05:51发布

I have;

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

Is there a (easy) way to retrieve the generic type of the list?

标签: java generics
14条回答
时光乱了年华
2楼-- · 2018-12-31 06:38

Generally impossible, because List<String> and List<Integer> share the same runtime class.

You might be able to reflect on the declared type of the field holding the list, though (if the declared type does not itself refer to a type parameter whose value you don't know).

查看更多
步步皆殇っ
3楼-- · 2018-12-31 06:39

At runtime, no, you can't.

However via reflection the type parameters are accessible. Try

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

The method getGenericType() returns a Type object. In this case, it will be an instance of ParametrizedType, which in turn has methods getRawType() (which will contain List.class, in this case) and getActualTypeArguments(), which will return an array (in this case, of length one, containing either String.class or Integer.class).

查看更多
低头抚发
4楼-- · 2018-12-31 06:40

If you need to get the generic type of a returned type, I used this approach when I needed to find methods in a class which returned a Collection and then access their generic types:

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]);
                    }
                }
            }
        }

    }

}

This outputs:

Generic type is class java.lang.String

查看更多
深知你不懂我心
5楼-- · 2018-12-31 06:40

As others have said, the only correct answer is no, the type has been erased.

If the list has a non-zero number of elements, you could investigate the type of the first element ( using it's getClass method, for instance ). That won't tell you the generic type of the list, but it would be reasonable to assume that the generic type was some superclass of the types in the list.

I wouldn't advocate the approach, but in a bind it might be useful.

查看更多
还给你的自由
6楼-- · 2018-12-31 06:42

For finding generic type of one field:

((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()
查看更多
旧时光的记忆
7楼-- · 2018-12-31 06:44

The generic type of a collection should only matter if it actually has objects in it, right? So isn't it easier to just do:

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

There's no such thing as a generic type in runtime, but the objects inside at runtime are guaranteed to be the same type as the declared generic, so it's easy enough just to test the item's class before we process it.

查看更多
登录 后发表回答