天天看點

java 反射 泛型機制 獲得泛型的實際類型(二)

二、 ParameterizedType 參數化的類型,顧名思義,就是給一個類型傳遞了類型參數,例 List<Contract> List接口被傳遞了Contract類型參數,那麼類型List<Contract>就是ParameterizedType,它可以做屬性的類型,做方法參數或傳回值的類型,也可以做泛型聲明的上邊界。 例如 public class GenericClass<T extends List<Contract>>裡的List<Contract>。由于泛型聲明可以聲明多個泛型參數,是以,參數化的類型也可以傳入多個類型參數,多個類型參數用,隔開。例如著名的Map定義的泛型參數是K和V 可以傳入Map<String,Contract>等等.如果屬性或方法參數聲明的資料給類型傳遞了類型參數,則field.getGenericType method.getGenericParameterType傳回Type 就是 instanceof ParameterizedType. ptype.getActualTypeArguments() :Type[]傳回每個傳入的類型參數,傳回值的長度取決于泛型聲明時聲明了幾個形式泛型參數。本文提出的問題便是基于這一點來嘗試解決的。ptype.getRawType() type傳回的是<>外的類型 即接收類型參數的類型,如List,Map.

三、WildcardType 這種類型用來處理參數化類型裡,對類型參數範圍的描述。例如一個方法的泛型參數是 Map<? extends Number,? super Contract>,此時 <> 裡用逗号隔開兩個對象都是WildcardType的執行個體。對每一個WildcardType對象(驗證type instanceof WildcardType==true) wtype.getUpperBounds():Type[]傳回上邊界類型(預設是Object.class),wtype.getLowerBounds():Type[]傳回下邊界類型。

說了這麼多,邏輯太繞了,本來就很難說清楚。隻有多測試多使用才能體會到。下面給一個我寫的方法,這個方法用來通路一個Collection接口類型的Field,假定該Field使用了泛型,然後傳回Collection的類型參數具體是什麼,即傳回客戶類指定的集合元素的類型。注意,的确隻能在運作時才能确定具體類型,本方法隻能獲得泛型的邊界,然後用上邊界類型來構造對象。如果一個使用了泛型的屬性剛好就像List<Contract>一樣,那麼讀取到Contract.class是輕而易舉的,因為這個泛型參數的邊界是固定的。

public Class getGenericTypeBounds(Field field)

throws TypeResolveException{

Type type = field.getGenericType();

if(type instanceof Class){

throw new TypeResolveException(field.getDeclaringClass().getName()+"屬性"

+field.getName()+" 沒有使用泛型或者 使用了rawtype但是沒有指定泛型實參。");

}

else if(type instanceof GenericArrayType){

type = ((GenericArrayType)type).getGenericComponentType();

}

else if(type instanceof TypeVariable<?>){

type = ((TypeVariable<?>)type).getBounds()[0];

}

else if(type instanceof ParameterizedType){

ParameterizedType ptype = (ParameterizedType)type;

Type[] types = ptype.getActualTypeArguments();

if(types==null || types.length==0){

throw new TypeResolveException(field.getDeclaringClass().getName()+"的集合屬性"

+field.getName()+" 所引用的泛型類型沒有指定泛型實參取值。");

}

if(types.length>1){

throw new TypeResolveException(field.getDeclaringClass().getName()+"的集合屬性"

+field.getName()+" 所引用的泛型類型 指定的泛型實參取值多于1個。");

}

type = ptype.getActualTypeArguments()[0];//隻有這個方法的傳回值才可能是 WildcardType

}

while(!(type instanceof Class)){

if(type instanceof WildcardType){

type = ((WildcardType)type).getUpperBounds()[0];

}

else if(type instanceof TypeVariable<?>){

type = ((TypeVariable<?>)type).getBounds()[0];

}

else if(type instanceof ParameterizedType){

ParameterizedType ptype = (ParameterizedType)type;

Type[] types = ptype.getActualTypeArguments();

if(types==null||types.length==0){

return Object.class;

}

if(types.length>1){

throw new TypeResolveException(field.getDeclaringClass().getName()+"的集合屬性"

+field.getName()+"引用到的泛型"+ptype+"的實參數量多于1個");

}

type = ptype.getActualTypeArguments()[0];

}

else if(type instanceof GenericArrayType ){

type = ((GenericArrayType)type).getGenericComponentType();

}

}

return (Class)type;

}