2009-07-14 75 views
5

我想在運行時使用反射來獲取集合的通用類型。在運行時指定通用集合類型參數(Java反射)

代碼(JAVA):

Field collectionObject = object.getClass().getDeclaredField(
    collectionField.getName()); 
//here I compare to see if a collection 
if (Collection.class.isAssignableFrom(collectionObject.getType())) { 
    // here I have to use the generic type of the collection 
    // to see if it's from a specific type - in this case Persistable 
    if (Persistable.class.isAssignableFrom(GENERIC_TYPE_COLLECTION.class)) { 
    } 
} 

是否有在運行時獲得泛型類型的集合在Java中的一種方式?在我的情況下,我需要該集合的泛型類型的.class。

在此先感謝!

+0

我正面臨着類似的問題,這終於爲我解決了這個問題:http://stackoverflow.com/a/183232/639119 – Zds 2012-10-04 18:43:22

回答

17

Type erasure表示關於對象的通用類型的信息在執行時根本不存在。

(鏈接是安格朗格Java Generics FAQ的相關部分應回答幾乎每一個問題,你可能問Java泛型:)

但是,你不是在一個對象的類型很感興趣 - 您對字段的類型感興趣。我誤解了這個問題,雖然答案已被接受,但我希望通過修正它來彌補現在:)

如果該字段本身不使用類型參數,則可以完成。例如:

import java.lang.reflect.*; 
import java.util.*; 

public class Test 
{ 
    public List<String> names; 

    public static void main(String [] args) 
     throws Exception // Just for simplicity! 
    { 
     Field field = Test.class.getDeclaredField("names"); 

     ParameterizedType type = (ParameterizedType) field.getGenericType(); 

     // List 
     System.out.println(type.getRawType()); 

     // Just String in this case 
     for (Type typeArgument : type.getActualTypeArguments()) 
     { 
      System.out.println(" " + typeArgument); 
     } 
    } 
} 

如果該字段是一類T與現場爲List<T>那麼你就必須知道該實例的類型參數,以便知道集合中的類型參數。

將此轉換爲您所需的代碼雖然有點棘手 - 您確實需要知道集合類中的類型參數。舉例來說,如果有人宣稱:

public class StringCollection implements Collection<String> 

,然後有StringCollection類型的字段,該字段本身不會有任何類型的參數。然後你需要遞歸地檢查getGenericSuperTypegetGenericInterfaces,直到找到你想要的。

雖然這是可能的,但確實不會那麼容易。如果我是你,我會嘗試改變你的設計,這樣你就不需要這個。

+1

遞歸檢查確實不容易,有很多案例需要考慮。這只是第一步,接下來你需要一個isAssignableFrom等價物來處理泛型。我不會推薦嘗試自己實現它。我寫了一個爲你做這個的庫,叫做gentyref。請參閱http://code.google.com/p/gentyref/。 – 2010-06-08 21:28:12

0

您可以從Field.getGenericType中獲得讀取對象的字段的通用類型。請注意,該字段可能是一個原始類型,是一種罕見的類型(通用但具有一般的參數是原始的),使用實例的類型,使用通配符等。

0

複製自我的帖子:https://stackoverflow.com/questions/1004022/java-generic-class-determine-type/1005283#1005283

我已經使用了一個類似的解決方案,他在這裏解釋了幾個項目,並發現它非常有用。

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

它的JIST使用以下,以確定在運行時類型參數:

public Class returnedClass { 
    ParameterizedType parameterizedType = 
    (ParameterizedType) getClass().getGenericSuperClass(); 
return (Class) parameterizedtype.getActualTypeArguments()[0]; 
} 
9

您絕對可以做你想做的。類型擦除意味着您無法檢查集合的實例的泛型類型,但您可以肯定地檢查字段的泛型類型。

class Thing { 
    List<Persistable> foo; 
} 


Field f = Thing.class.getDeclaredField("foo"); 
if(Collection.class.isAssignableFrom(f.getType()) { 
    Type t = f.getGenericType(); 
    if(t instanceof ParameterizedType) { 
    Class genericType = (Class)((ParameterizedType)t).getActualTypeArguments()[0]; 
    if(Persistable.class.isAssignableFrom(genericType)) 
     return true; 
    } 
} 

有很多的事情可以去錯在這裏,例如,如果你有

Class Thing<T> { 
    List<T> foo; 
} 

那麼上面將無法正常工作。

+1

我猜這條線: Class genericType =(Class)((ParameterizedType)t).getActualTypeArguments [0]; 應該是 類genericType =(Class)((ParameterizedType)t).getActualTypeArguments()[0]; ? – andersonbd1 2009-12-15 15:55:50