作者: Jakob Jenkov 譯者:葉文海(yewenhai@gmail.com)
我常常在一些文章以及論壇中讀到說 Java 泛型信息在編譯期被擦除(erased)所以你無法在運(yùn)行期獲得有關(guān)泛型的信息。其實(shí)這種說法并不完全正確的,在一些情況下是可以在運(yùn)行期獲取到泛型的信息。這些情況其實(shí)覆蓋了一些我們需要泛型信息的需求。在本節(jié)中我們會(huì)演示一下這些情況。
下面是兩個(gè)典型的使用泛型的場(chǎng)景: 1、聲明一個(gè)需要被參數(shù)化(parameterizable)的類/接口。 2、使用一個(gè)參數(shù)化類。
當(dāng)你聲明一個(gè)類或者接口的時(shí)候你可以指明這個(gè)類或接口可以被參數(shù)化, java.util.List 接口就是典型的例子。你可以運(yùn)用泛型機(jī)制創(chuàng)建一個(gè)標(biāo)明存儲(chǔ)的是 String 類型 list,這樣比你創(chuàng)建一個(gè) Object 的l ist 要更好。
當(dāng)你想在運(yùn)行期參數(shù)化類型本身,比如你想檢查 java.util.List 類的參數(shù)化類型,你是沒有辦法能知道他具體的參數(shù)化類型是什么。這樣一來這個(gè)類型就可以是一個(gè)應(yīng)用中所有的類型。但是,當(dāng)你檢查一個(gè)使用了被參數(shù)化的類型的變量或者方法,你可以獲得這個(gè)被參數(shù)化類型的具體參數(shù)??傊?/p>
你不能在運(yùn)行期獲知一個(gè)被參數(shù)化的類型的具體參數(shù)類型是什么,但是你可以在用到這個(gè)被參數(shù)化類型的方法以及變量中找到他們,換句話說就是獲知他們具體的參數(shù)化類型。 在下面的段落中會(huì)向你演示這類情況。
如果你獲得了 java.lang.reflect.Method 對(duì)象,那么你就可以獲取到這個(gè)方法的泛型返回類型信息。如果方法是在一個(gè)被參數(shù)化類型之中(譯者注:如 T fun())那么你無法獲取他的具體類型,但是如果方法返回一個(gè)泛型類(譯者注:如 List fun())那么你就可以獲得這個(gè)泛型類的具體參數(shù)化類型。你可以在“Java Reflection: Methods”中閱讀到有關(guān)如何獲取Method對(duì)象的相關(guān)內(nèi)容。下面這個(gè)例子定義了一個(gè)類這個(gè)類中的方法返回類型是一個(gè)泛型類型:
public class MyClass {
protected List<String> stringList = ...;
public List<String> getStringList(){
return this.stringList;
}
}
我們可以獲取 getStringList()方法的泛型返回類型,換句話說,我們可以檢測(cè)到 getStringList()方法返回的是 List 而不僅僅只是一個(gè) 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);
}
}
這段代碼會(huì)打印出 “typeArgClass = java.lang.String”,Type[]數(shù)組typeArguments 只有一個(gè)結(jié)果 – 一個(gè)代表 java.lang.String 的 Class 類的實(shí)例。Class 類實(shí)現(xiàn)了 Type 接口。
你同樣可以通過反射來獲取方法參數(shù)的泛型類型,下面這個(gè)例子定義了一個(gè)類,這個(gè)類中的方法的參數(shù)是一個(gè)被參數(shù)化的 List:
public class MyClass {
protected List<String> stringList = ...;
public void setStringList(List<String> list){
this.stringList = list;
}
}
你可以像這樣來獲取方法的泛型參數(shù):
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);
}
}
}
這段代碼會(huì)打印出”parameterArgType = java.lang.String”。Type[]數(shù)組 parameterArgTypes 只有一個(gè)結(jié)果 – 一個(gè)代表 java.lang.String 的 Class 類的實(shí)例。Class 類實(shí)現(xiàn)了Type接口。
同樣可以通過反射來訪問公有(Public)變量的泛型類型,無論這個(gè)變量是一個(gè)類的靜態(tài)成員變量或是實(shí)例成員變量。你可以在“Java Reflection: Fields”中閱讀到有關(guān)如何獲取 Field 對(duì)象的相關(guān)內(nèi)容。這是之前的一個(gè)例子,一個(gè)定義了一個(gè)名為 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);
}
}
這段代碼會(huì)打印出”fieldArgClass = java.lang.String”。Type[]數(shù)組 fieldArgClass 只有一個(gè)結(jié)果 – 一個(gè)代表 java.lang.String 的 Class 類的實(shí)例。Class 類實(shí)現(xiàn)了 Type 接口。
本文鏈接地址: Java Reflection(九):泛型