获取java.util.List的泛型类型

时间:2009-12-21 21:08:43

标签: java generics

我有;

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

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

14 个答案:

答案 0 :(得分:367)

如果那些实际上是某个类的字段,那么你可以在反思的帮助下得到它们:

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

您也可以为参数类型和方法的返回类型执行此操作。

但是如果他们在你需要了解它们的类/方法的同一范围内,那么就没有必要知道它们,因为你已经自己声明了它们。

答案 1 :(得分:17)

简答:不。

这可能是重复的,现在找不到合适的。

Java使用称为类型擦除的东西,这意味着在运行时两个对象都是等价的。编译器知道列表包含整数或字符串,因此可以维护类型安全的环境。此信息在运行时丢失(基于对象实例),列表仅包含“对象”。

你可以找到关于这个类的一些信息,它可以通过哪种类型进行参数化,但通常这只是扩展“对象”的任何东西,即任何东西。如果将类型定义为

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

AClass.class只会包含参数A受MyClass限制的事实,但更重要的是,没有办法告诉。

答案 2 :(得分:17)

您也可以对方法参数执行相同的操作:

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

答案 3 :(得分:9)

如果你需要获得返回类型的泛型类型,当我需要在返回Collection的类中查找方法然后访问它们的泛型类型时,我使用了这种方法:

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

    }

}

输出:

  

泛型类型是类java.lang.String

答案 4 :(得分:9)

查找一个字段的泛型类型:

((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()

答案 5 :(得分:7)

集合的泛型类型应该只有它实际上有对象,对吧?所以不容易做到:

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

在运行时没有泛型类型,但运行时内部的对象保证与声明的泛型相同,所以只需测试项目&# 39;在我们处理之前的课程。

答案 6 :(得分:6)

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

答案 7 :(得分:4)

在运行时,不,你不能。

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

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

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

答案 8 :(得分:4)

有同样的问题,但我使用了instanceof。这样做了:

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

这涉及使用未经检查的强制转换,因此只有当您知道它是一个列表时才会这样做,以及它可以是什么类型。

答案 9 :(得分:3)

通常不可能,因为List<String>List<Integer>共享相同的运行时类。

尽管如此(如果声明的类型本身并不引用您不知道其值的类型参数),您可能能够反映出包含该列表的字段的声明类型。

答案 10 :(得分:2)

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

如果列表具有非零数量的元素,则可以调查第一个元素的类型(例如,使用它的getClass方法)。这不会告诉你列表的泛型类型,但是假设泛型类型是列表中某些类型的超类是合理的。

我不提倡这种方法,但在绑定中它可能有用。

答案 11 :(得分:1)

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(fieldGenericType));
            }
        }
    }

    //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();
    }
}

答案 12 :(得分:0)

答案 13 :(得分:0)

使用Reflection获取Field,然后您可以执行:field.genericType以获取包含有关泛型信息的类型。