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

Thy*_*hys 246 java generics

我有;

List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)

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

Bal*_*usC 387

如果那些实际上是某个类的字段,那么你可以通过一些反思来获得它们:

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 当然有一些情况下,这是非常有用的.例如,无配置的ORM框架. (16认同)
  • ..可以使用Class#getDeclaredFields()获取所有字段,而无需知道字段名称. (3认同)
  • @Oleg您的变量使用“&lt;?&gt;”(通配符类型)而不是“&lt;Class&gt;”(类类型)。将“&lt;?&gt;”替换为“&lt;Class&gt;”或任何“&lt;E&gt;”。 (2认同)
  • 10年后仍然有用 (2认同)

fal*_*tro 18

简答:不.

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

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

你可以找到一些关于类的信息,它可以通过参数化来获得什么类型,但通常这只是扩展"对象"的任何东西,即任何东西.如果将类型定义为

class <A extends MyClass> AClass {....}
Run Code Online (Sandbox Code Playgroud)

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

  • 如果未指定泛型的具体类,那将是正确的;在他的例子中,他明确地将列表声明为 `List&lt;Integer&gt;` 和 `List&lt;String&gt;`;在这些情况下,类型擦除不适用。 (2认同)

tsa*_*wei 18

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

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
Run Code Online (Sandbox Code Playgroud)


Moh*_*shi 10

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

((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()
Run Code Online (Sandbox Code Playgroud)


Ara*_*yan 9

如果你需要获得返回类型的泛型类型,当我需要在返回a 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]);
                    }
                }
            }
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

这输出:

泛型类型是类java.lang.String


Ste*_*e K 8

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

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
Run Code Online (Sandbox Code Playgroud)

在运行时没有泛型类型的东西,但运行时内部的对象保证与声明的泛型相同,所以在处理它之前只需测试项的类就很容易了.

  • 如果你有一个空集合?或者如果你有一个带有整数和字符串的Collection <Object>? (5认同)

ggb*_*667 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);
   }
}
Run Code Online (Sandbox Code Playgroud)


And*_*ndy 5

有同样的问题,但我使用了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");
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

这涉及使用未经检查的强制转换,因此仅当您知道它是一个列表以及它可以是什么类型时才执行此操作。