2009-11-19 61 views
5

我在一個類中定義的方法:Java反射:我的Collection包含什麼?

public void setCollection(Collection<MyClass>); 

,並在另一個類

public void setCollection(Collection<OtherClass>); 

(真的,很多類似的類的)

所有在班與同超類,並且我在支持類中有一個方法,我想調用此方法並將其設置爲具有正確類類型的項。現在,我可以說我做

Method setter = ...; 
Class<?> paramClass = setter.getParameterTypes()[0]; // Is Collection in this case 
if(paramClass.equals(Collection.class)) { 
    HashSet col = new HashSet(); 
    // fill the set with something 
    setter.invoke(this, col); 
} 

設置集合,但我怎麼想出這個集合中的對象應該是屬於什麼階級?

乾杯

回答

9
Method.getGenericParameterTypes(); 

返回參數接受的類型數組。複雜性從那裏呈指數增長。

在特定情況下,這會工作:

Method m = Something.class.getMethod("setCollection", Collection.class); 
    Class<?> parameter = (Class<?>) ((ParameterizedType) m.getGenericParameterTypes()[0]).getActualTypeArguments()[0]; 

但也有很多潛在的陷阱的存在,取決於參數是如何聲明的。如果這是一個簡單的例子,那很好。如果不是,那麼在getGenericParameterTypes()方法和getActualTypeArguments()方法中都有一些類型需要考慮。它變得非常多毛和難看得很快。

+0

謝謝一堆,這解決了我的問題!此處增加的複雜性會降低我整體的複雜度,所以我會爲你效勞並真誠地感謝你。 :-) – niklassaers 2009-11-19 16:40:14

1

的Java實現與類型擦除泛型。編譯器僅將此類型信息用於安全檢查,字節碼不包含有關泛型的任何信息。因此,運行時也不知道它,所以你不能通過反射來檢索它。

你可以找到一些額外的信息here

更新

要糾正自己,考慮這個方法:

public <T> String doSomething(T first, int second) { 
    return first.toString(); 
} 

在字節碼,這將具有以下特徵(注意T形):

<T:Ljava/lang/Object;>(TT;I)Ljava/lang/String 

所以我上面說的只是這個例外。

0

你似乎已經知道二傳手了。所以在我看來,在這種情況下,MyClass和OtherClass(不是集合,但是項目)共享類似接口的某些東西。 在這種情況下,您並不需要知道確切的類型。

0

正如candiru已經解釋的那樣,「集合類型」被刪除,在運行時它只是對象類型的集合。

如果你被允許在你的子類稍微改變消息簽名

public void setCollection(Collection<T> aCollection, Class<T> elementType); 

,那麼你可以通過持有的「集合類型」的信息,第二個參數,用法是這樣的:

public void setCollection(Collection<MyClass> myClassCollection, 
          Class<MyClass> clazz); 

,並使用它:

Collection<MyClass> myClassCollection = new ArrayList<MyClassCollection>(); 
setCollection(myClassCollection, MyClass.class); 

但在另一方面 - 烏蘇同盟你不必關心它,因爲類型在運行時被擦除,只要你沒有被編譯器捕獲到,你可以把任何類型的對象放在參數集合中;)

2

我會考慮將setCollection方法移出到它們自己的類中,然後做更像這樣的事情(您可以將其更改爲一次創建整個集合,而不是一次將其作爲元素進行創建)。

這消除了反射,並確保它在編譯時類型安全。我可能會誤解你在做什麼,但我想我明白了。 「init」方法將是輔助方法(至少如果我明白你的意圖)。

public class Main 
{ 
    public static void main(String[] args) 
    { 
     List<Car> car; 
     List<Bar> bar; 

     car = new ArrayList<Car>(); 
     bar = new ArrayList<Bar>(); 
     init(car, new CarCreator()); 
     init(bar, new BarCreator()); 
    } 

    private static <T> void init(final List<T> list, 
           final Creator<T> creator) 
    { 
     for(int i = 0; i < 10; i++) 
     { 
      final T instance; 

      instance = creator.newInstance(i); 
      list.add(instance); 
     } 
    } 
} 

interface Foo 
{  
} 

class Bar implements Foo 
{ 
} 

class Car implements Foo 
{ 
} 

interface Creator<T> 
{ 
    T newInstance(int i); 
} 

class BarCreator 
    implements Creator<Bar> 
{ 
    public Bar newInstance(final int i) 
    { 
     return (new Bar()); 
    } 
} 

class CarCreator 
    implements Creator<Car> 
{ 
    public Car newInstance(final int i) 
    { 
     return (new Car()); 
    } 
}