2013-03-05 55 views
0

我需要获取集合物品的类型。 用于检索单个实例我使用下面的代码的类:鉴于一个集合获取物品的类型(Java)

classUnderTest.getName() 

但是,我怎么能检索类以下收集的物品?

Collection collection = (Collection) getCollection.invoke(instance1); 
+0

?你能用一个例子来解释吗? – 2013-03-05 09:27:41

回答

0

不能由于Type Erasure,在运行时获取/推断集合的通用类型。泛型在编译时安全,类型信息在运行时被擦除。

在运行时,实例的集合是Object,它并不关心运行时的实际类型。

0

由于通用擦除,征收对象不知道什么类型的项目必须是,他们现在只是什么。根据您的需要,一种解决方案可能是以难以实现的方式进行并找到集合中所有项目的最具体的超类(或超级接口)。

但是,您是否真的需要知道收集项目的类型?

+0

是的,我需要,因为我正在为不与继承链接的不同类创建一些测试方法。 – daniele 2013-03-05 09:25:17

+0

然后对所有每个类的测试用例都有一个Map (或一个不同的接口),并运行各个项目的类。你仍然需要找到物品类或是一个简单的item.getClass()。getName()是否足够(每个物品)? – 2013-03-05 09:35:02

0

简短的答案是,你不能。

泛型类型参数不记录为该类型的实例(对象)的一部分。 (请阅读“type erasure”...)此外,您的示例无论如何都使用原始类型。

您可以挑选(非空)集合中的某个元素并获取该集合的类型,但它不会告诉您有关其他元素的类型的任何信息。 (它们可以是相同的或不同的)。如果集合是空的或包含引用,则甚至不可靠地执行该操作。

无论如何,这会给你一个集合的第一个元素的类型。

Collection c = ... 
    Iterator it = c.iterator(); 
    if (c.hasNext()) { 
     Class clazz = c.next().getClass(); 
     ... 
    } 

你可以遍历整个集合和(有一定难度)找出它们都符合的公共类或接口。但即使这样也不一定与声明的元素类型相同。

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是类层次结构中收集项目的最大深度。

0

你不能。在Java中,没有办法在运行时检索泛型类型。它被称为Type Erasure

但你可以遍历Collection并获得最一般的类型。但即使你这样做,你也无法将该类型作为泛型类型传递。

最好的办法是抑制警告并确保没有任何非法行为进入该方法。

0

的答案是从职位大多数人都表示很明显......这是 你不能/在运行时由于Type Erasure

推断出通用类型的集合,但是,我想证明什么这意味着

假设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的结果......这MEA NS它能够当 集合对象是使用适当的通用名称参数采集

推断但是,如果我们把,

Collection<?> collection = new ArrayList<String>(); 

然后它会编译得很好,但上运行,你会得到下面的异常..

sun.reflect.generics.reflectiveObjects.WildcardTypeImpl cannot be cast to java.lang.Class 

这是异常抛出为什么你需要一个运行时类型擦除

相关问题