2013-03-05 33 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 

這是異常拋出爲什麼你需要一個運行時類型擦除

相關問題