原文地址 作者: Jakob Jenkov 譯者:葉文海([email protected])
我常常在一些文章以及論壇中讀到說Java泛型信息在編譯期被擦除(erased)所以你無法在運行期獲得有關泛型的信息。其實這種說法並不完全正確的,在一些情況下是可以在運行期獲取到泛型的信息。這些情況其實覆蓋了一些我們需要泛型信息的需求。在本節中我們會演示一下這些情況。
1. 運用泛型反射的經驗法則
下面是兩個典型的使用泛型的場景:
1、聲明一個需要被參數化(parameterizable)的類/接口。
2、使用一個參數化類。
當你聲明一個類或者接口的時候你可以指明這個類或接口可以被參數化,java.util.List接口就是典型的例子。你可以運用泛型機制創建一個標明存儲的是String類型list,這樣比你創建一個Object的list要更好。
當你想在運行期參數化類型本身,比如你想檢查java.util.List類的參數化類型,你是沒有辦法能知道他具體的參數化類型是什麼。這樣一來這個類型就可以是一個應用中所有的類型。但是,當你檢查一個使用了被參數化的類型的變量或者方法,你可以獲得這個被參數化類型的具體參數。總之:
你不能在運行期獲知一個被參數化的類型的具體參數類型是什麼,但是你可以在用到這個被參數化類型的方法以及變量中找到他們,換句話說就是獲知他們具體的參數化類型。
在下面的段落中會向你演示這類情況。
2. 泛型方法返回類型
如果你獲得了java.lang.reflect.Method對象,那麼你就可以獲取到這個方法的泛型返回類型信息。如果方法是在一個被參數化類型之中(譯者注:如T fun())那麼你無法獲取他的具體類型,但是如果方法返回一個泛型類(譯者注:如List fun())那麼你就可以獲得這個泛型類的具體參數化類型。你可以在“Java Reflection: Methods”中閱讀到有關如何獲取Method對象的相關內容。下面這個例子定義了一個類這個類中的方法返回類型是一個泛型類型:
public class MyClass {
protected List<String> stringList = ...;
public List<String> getStringList(){
return this.stringList;
}
}
我們可以獲取getStringList()方法的泛型返回類型,換句話說,我們可以檢測到getStringList()方法返回的是List而不僅僅只是一個List。如下例:
Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();
if(returnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgClass = " + typeArgClass);
}
}
這段代碼會打印出 “typeArgClass = java.lang.String”,Type[]數組typeArguments只有一個結果 – 一個代表java.lang.String的Class類的實例。Class類實現了Type接口。
3. 泛型方法參數類型
你同樣可以通過反射來獲取方法參數的泛型類型,下面這個例子定義了一個類,這個類中的方法的參數是一個被參數化的List:
public class MyClass {
protected List<String> stringList = ...;
public void setStringList(List<String> list){
this.stringList = list;
}
}
你可以像這樣來獲取方法的泛型參數:
method = Myclass.class.getMethod("setStringList", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for(Type genericParameterType : genericParameterTypes){
if(genericParameterType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericParameterType;
Type[] parameterArgTypes = aType.getActualTypeArguments();
for(Type parameterArgType : parameterArgTypes){
Class parameterArgClass = (Class) parameterArgType;
System.out.println("parameterArgClass = " + parameterArgClass);
}
}
}
這段代碼會打印出”parameterArgType = java.lang.String”。Type[]數組parameterArgTypes只有一個結果 – 一個代表java.lang.String的Class類的實例。Class類實現了Type接口。
4. 泛型變量類型
同樣可以通過反射來訪問公有(Public)變量的泛型類型,無論這個變量是一個類的靜態成員變量或是實例成員變量。你可以在“Java Reflection: Fields”中閱讀到有關如何獲取Field對象的相關內容。這是之前的一個例子,一個定義了一個名爲stringList的成員變量的類。
public class MyClass {
public List<String> stringList = ...;
}
Field field = MyClass.class.getField("stringList");
Type genericFieldType = field.getGenericType();
if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
for(Type fieldArgType : fieldArgTypes){
Class fieldArgClass = (Class) fieldArgType;
System.out.println("fieldArgClass = " + fieldArgClass);
}
}
這段代碼會打印出”fieldArgClass = java.lang.String”。Type[]數組fieldArgClass只有一個結果 – 一個代表java.lang.String的Class類的實例。Class類實現了Type接口。
原創文章,轉載請註明: 轉載自併發編程網 – ifeve.com
本文鏈接地址: Java Reflection(九):泛型