我需要获取集合项的类型。 为了检索单个实例的类,我使用以下代码:
classUnderTest.getName()
但是,我如何检索以下集合的项目类?
Collection collection = (Collection) getCollection.invoke(instance1);
答案 0 :(得分:0)
由于通用擦除,Collection对象不知道必须的项目类型,只知道它们现在是什么类型。根据您的需要,一个解决方案可能是以艰难的方式去做,并找到集合中所有项目的最具体的超类(或超接口)。
但是,你真的需要知道收集项的类型吗?
答案 1 :(得分:0)
由于Type Erasure,您无法在运行时获取/推断集合的泛型类型。泛型用于编译时安全性,类型信息在运行时被擦除。
在运行时,实例为Object
用于收集,它不关心运行时的实际类型。
答案 2 :(得分:0)
简短的回答是,你不能。
通用类型参数不会记录为该类型的实例(对象)的一部分。 (阅读“type erasure”......)此外,您的示例无论如何都在使用原始类型。
您可以选择(非空)集合的某些元素并获取其类型,但它不会告诉您有关其他元素类型的任何信息。 (它们可以是相同的......或者不同的。)如果集合是空的或包含null
引用,你甚至无法可靠地执行此操作。
无论如何,这将为您提供集合的第一个元素的类型。
Collection c = ...
Iterator it = c.iterator();
if (c.hasNext()) {
Class clazz = c.next().getClass();
...
}
你可以遍历整个集合并(有一些困难)找出它们都符合的公共类或接口。但即便如此,也不一定与声明的元素类型相同。
答案 3 :(得分:0)
一般来说,你不能这样做。例如,该集合可以是空的或仅由空值组成。那么,接口呢?可能有多个接口,这些接口对所有集合元素都是通用的。
但是,在您的情况下,以下其中一项可能会有所帮助:
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是类层次结构中集合项的最大深度。
答案 4 :(得分:0)
但您可以迭代Collection
并获得最常规的类型。但即使你这样做,也无法将该类型作为泛型传递。
你最好的选择是压制警告并确保没有任何违法行为传递给方法。
答案 5 :(得分:0)
从大多数人所说的帖子中可以看出答案很明显......就是这样 由于Type Erasure
,您无法在运行时获取/推断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();
}
}
它将打印类java.lang.String 作为结果...这意味着它能够推断出何时 Collection对象使用正确的泛型参数Collection
但是,如果我们放,
Collection<?> collection = new ArrayList<String>();
然后它会编译得很好,但在运行时你会得到以下异常..
sun.reflect.generics.reflectiveObjects.WildcardTypeImpl cannot be cast to java.lang.Class
这是运行时类型擦除
引发的异常