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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1942644/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 01:38:44  来源:igfitidea点击:

Get generic type of java.util.List

javagenerics

提问by Thizzer

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?

有没有(简单的)方法来检索列表的通用类型?

采纳答案by BalusC

If those are actually fields of a certain class, then you can get them with a little help of reflection:

如果这些实际上是某个类的字段,那么您可以通过反射获得它们:

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

You can also do that for parameter types and return type of methods.

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

But if they're inside the same scope of the class/method where you need to know about them, then there's no point of knowing them, because you already have declared them yourself.

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

回答by falstro

Short answer: no.

简短的回答:没有。

This is probably a duplicate, can't find an appropriate one right now.

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

Java uses something called type erasure, which means at runtime both objects are equivalent. The compiler knows the lists contain integers or strings, and as such can maintain a type safe environment. This information is lost (on an object instance basis) at runtime, and the list only contain 'Objects'.

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

You CAN find out a little about the class, what types it might be parametrized by, but normally this is just anything that extends "Object", i.e. anything. If you define a type as

你可以稍微了解一下这个类,它可能被参数化的类型,但通常这只是扩展“Object”的任何东西,即任何东西。如果您将类型定义为

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

AClass.class will only contain the fact that the parameter A is bounded by MyClass, but more than that, there's no way to tell.

AClass.class 将只包含参数 A 受 MyClass 限制的事实,但除此之外,无法判断。

回答by peter.murray.rust

回答by Chris Arguin

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.

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

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

我不提倡这种方法,但在某种情况下它可能有用。

回答by meriton

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

一般不可能,因为List<String>List<Integer>共享同一个运行时类。

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

不过,您也许可以考虑包含列表的字段的声明类型(如果声明的类型本身不引用您不知道其值的类型参数)。

回答by Scott Morrison

At runtime, no, you can't.

在运行时,不,你不能。

However via reflection the type parameters areaccessible. 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.classor Integer.class).

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

回答by tsaixingwei

You can do the same for method parameters as well:

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

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

回答by Ashish

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

回答by Steve K

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.

运行时没有泛型类型这样的东西,但是运行时内部的对象保证与声明的泛型类型相同,因此在我们处理它之前测试项目的类就足够容易了。

Another thing you can do is simply process the list to get members that are the right type, ignoring others (or processing them differently).

您可以做的另一件事是简单地处理列表以获得正确类型的成员,忽略其他成员(或以不同方式处理它们)。

Map<Class<?>, List<Object>> classObjectMap = myCollection.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.groupingBy(Object::getClass));

// Process the list of the correct class, and/or handle objects of incorrect
// class (throw exceptions, etc). You may need to group subclasses by
// filtering the keys. For instance:

List<Number> numbers = classObjectMap.entrySet().stream()
        .filter(e->Number.class.isAssignableFrom(e.getKey()))
        .flatMap(e->e.getValue().stream())
        .map(Number.class::cast)
        .collect(Collectors.toList());

This will give you a list of all items whose classes were subclasses of Numberwhich you can then process as you need. The rest of the items were filtered out into other lists. Because they're in the map, you can process them as desired, or ignore them.

这将为您提供其类是其子类的所有项目的列表,Number然后您可以根据需要对其进行处理。其余项目被过滤到其他列表中。因为它们在地图中,您可以根据需要处理它们,或者忽略它们。

If you want to ignore items of other classes altogether, it becomes much simpler:

如果你想完全忽略其他类的项目,它会变得简单得多:

List<Number> numbers = myCollection.stream()
    .filter(Number.class::isInstance)
    .map(Number.class::cast)
    .collect(Collectors.toList());

You can even create a utility method to insure that a list contains ONLY those items matching a specific class:

你甚至可以创建一个实用方法来确保列表只包含那些匹配特定类的项目:

public <V> List<V> getTypeSafeItemList(Collection<Object> input, Class<V> cls) {
    return input.stream()
            .filter(cls::isInstance)
            .map(cls::cast)
            .collect(Collectors.toList());
}

回答by Aram Kocharyan

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 Collectionand then access their generic types:

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

    }

}

This outputs:

这输出:

Generic type is class java.lang.String

泛型类型是类 java.lang.String