我需要获取集合项目的类型。为了检索单个实例的类,我使用以下代码:
classUnderTest.getName()
但是,我怎样才能检索以下集合的项目的类?
Collection collection = (Collection) getCollection.invoke(instance1);
我需要获取集合项目的类型。为了检索单个实例的类,我使用以下代码:
classUnderTest.getName()
但是,我怎样才能检索以下集合的项目的类?
Collection collection = (Collection) getCollection.invoke(instance1);
由于通用擦除,Collection 对象不知道项目必须是什么类型,只知道它们现在是什么类型。根据您的需要,一种解决方案可能是艰难地完成它并找到集合中所有项目的最具体的超类(或超接口)。
但是,您真的需要知道收藏品的类型吗?
由于Type Erasure ,您无法在运行时获取/推断 Collection 的泛型类型。泛型用于编译时安全,类型信息在运行时被擦除。
在运行时,实例Object
用于收集,它不关心运行时的实际类型。
简短的回答是你不能。
泛型类型参数不记录为该类型实例(对象)的一部分。(阅读“类型擦除”......)此外,您的示例无论如何都使用原始类型。
您可以选择(非空)集合的某些元素并获取其类型,但它不会告诉您有关其他元素类型的任何信息。(它们可能相同......或不同。)如果集合为空或包含null
引用,您甚至无法可靠地做到这一点。
无论如何,这将为您提供集合的第一个元素的类型。
Collection c = ...
Iterator it = c.iterator();
if (c.hasNext()) {
Class clazz = c.next().getClass();
...
}
您可以遍历整个集合并(有一些困难)找出它们都符合的公共类或接口。但即使这样也不一定与声明的元素类型相同。
一般来说,你不能这样做。例如,该集合可能是空的或仅由空值组成。另外,接口呢?可能存在所有集合元素共有的多个接口。
但是,以下其中一项可能会对您的情况有所帮助:
1)分析集合内容:假设集合是非空的,扫描集合中的所有项目并找到它们在类层次结构中的最低共同祖先。
2)获取泛型声明类型:如果您正在检查的对象被声明为某个类的数据成员(带有泛型),您可以在运行时使用反射评估其声明的泛型类型(参见Field.getGenericType())
- 编辑 -
只是为了练习,我实现了最低的共同祖先实用程序:
public static Class<?> getLCA(Collection<?> c) {
Class<?> res = null;
for (Object obj : c)
if (obj != null) {
Class<?> clazz = obj.getClass();
res = (res == null)? clazz : getLCA(res, clazz);
}
return res;
}
private static Class<?> getLCA(Class<?> classA, Class<?> classB) {
if (classA.isAssignableFrom(classB))
return classA;
if (classB.isAssignableFrom(classA))
return classB;
while (!classA.isAssignableFrom(classB))
classA = classA.getSuperclass();
return classA;
}
效率:O(n*h),其中 n 是集合大小,h 是类层次结构中集合项的最大深度。
你不能。在 Java 中,无法在运行时检索泛型类型。它被称为类型擦除。
但是您可以遍历Collection
并获得最通用的类型。但即使你这样做了,你也无法将该类型作为泛型类型传递。
您最好的选择是禁止警告并确保没有任何非法内容传递到方法中。
从大多数人所说的帖子中,答案非常明显......也就是说,由于类型擦除,您无法在运行时获取/推断 Collection 的泛型类型
但是,我想证明这意味着什么
假设we create a class MyClass
并这样做
Collection<String> collection = new ArrayList<String>();
public static void main(String[] args) {
Field stringListField = null;
try {
stringListField = MyClass.class.getDeclaredField("collection");
ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
System.out.println(stringListClass);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
它将打印class java.lang.String作为结果......这意味着它能够推断 Collection 对象何时使用正确的泛型参数 Collection
但是,如果我们说,
Collection<?> collection = new ArrayList<String>();
然后它会编译得很好但是在运行时你会得到以下异常..
sun.reflect.generics.reflectiveObjects.WildcardTypeImpl cannot be cast to java.lang.Class
这是运行时类型擦除引发的异常