利用反射操做泛型

反射+泛型有關的接口類型

Type直接子接口java

  • java.lang.reflect.ParameterizedType : 表示一種參數化的類型,好比Collection<String>, Collection<T> Collection<T[]>等
  • java.lang.reflect.GenericArrayType : 表示一種元素類型是參數化類型或者類型變量的數組類型, 好比 T[] 
  • java.lang.reflect.WildcardType : 表明一種通配符類型表達式, 好比?, ? extends Number, ? super Integer ( wildcard:「通配符」 )
  • java.lang.reflect.TypeVariable :是各類類型變量的公共父接口, Collection<T> 中的T, 可經過Class.getTypeParametes得到

全部類型都是Type類型子類數組

  • 原始類型 (raw types)【對應Class】
  • 參數化類型 (parameterizedtypes)【對應ParameterizedType】
  • 參數化數組類型 (array types)【對應GenericArrayType】
  • 類型變量 (type variables)【對應TypeVariable】
  • 基本數據類型(primitivetypes)【仍然對應Class】

ParameterizedType 接口類型的含義

表示參數化類型。好比:Map這種參數化類型 獲取參數化類型<>中的實際類型 源碼聲明:Type[] getActualTypeArguments(); 【注意】不管<>中有幾層<>嵌套,這個方法僅僅脫去最外層的<>以後剩下的內容就做爲這個方法的返回值。安全

ArrayList> al1  經過getActualTypeArguments()返回以後,脫去最外層的<>以後,剩餘的類型是ArrayList。所以對這個參數的返回類型是ParameterizedType。spa

ArrayList al2 經過getActualTypeArguments()返回以後,脫去最外層的<>以後,剩餘的類型是E。所以對這個參數的返回類型是TypeVariable。code

ArrayList al3  經過getActualTypeArguments()返回以後,脫去最外層的<>以後,剩餘的類型是String。所以對這個參數的返回類型是Class。對象

ArrayList al4  經過getActualTypeArguments()返回以後,脫去最外層的<>以後,剩餘的類型是? ExtendsNumber。所以對這個參數的返回類型是WildcardType。接口

ArrayList al5(){}  經過getActualTypeArguments()返回以後,脫去最外層的<>以後,剩餘的類型是E[]。所以對這個參數的返回類型是GenericArrayType。element

因此,可能得到各類各樣類型的實際參數,因此爲了統一,採用直接父類數組Type[]進行接收。開發

方法:get

Type getRawType(): 返回承載該泛型信息的對象, 如上面那個Map<String, String>承載範型信息的對象是Map

Type[] getActualTypeArguments(): 返回實際泛型類型列表, 如上面那個Map<String, String>實際範型列表中有兩個元素, 都是String,

getActualTypeArguments返回的有多是ParameterizedType,GenericArrayType,TypeVariable, WildCardType。

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

/**
 * @author yeweigen
 */
public class Test  {

    static class SuperClass<T>{}

    static class ParameterizedTypeCase<T> extends SuperClass<SuperClass<T>> {}

    static class TypeVariableCase<T> extends SuperClass<T> {}

    static class GenericArrayTypeCase<T> extends SuperClass<T[]> {}

    static class GenericArrayTypeCase1 extends SuperClass<String[]> {}

    public static void main(String [] args) {
        printActualTypeArguments(getParameterizedType(ParameterizedTypeCase.class));
        printActualTypeArguments(getParameterizedType(TypeVariableCase.class));
        printActualTypeArguments(getParameterizedType(GenericArrayTypeCase.class));
        printActualTypeArguments(getParameterizedType(GenericArrayTypeCase1.class));
    }

    public static ParameterizedType getParameterizedType(Class clazz) {
        Type type =  clazz.getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            return (ParameterizedType) type;
        }
        return null;
    }

    public static void printActualTypeArguments(ParameterizedType type) {
        if (type == null ) return;
        Type[] types = type.getActualTypeArguments();
        if (types[0] instanceof ParameterizedType) {
            System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof ParameterizedType");
        }
        if (types[0] instanceof TypeVariable) {
            System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof TypeVariable");
        }
        if (types[0] instanceof GenericArrayType) {
            System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof GenericArrayType");
        }
        if (types[0] instanceof Class) {
            System.out.println("First element of "+ type + " getActualTypeArguments() is instanceof Class");
        }
    }
}

Type getOwnerType(): 返回是誰的member.(上面那兩個最經常使用)

GenericArrayType 接口類型的含義

表示泛型數組類型。好比:void method(ArrayList[] al){…} 【注意】<>不能出如今數組的初始化中,即new數組以後不能出現<>,不然javac沒法經過。可是做爲引用變量或者方法的某個參數是徹底能夠的。 獲取泛型數組中元素的類型 源碼聲明:Type getGenericComponentType(); 【注意】不管從左向右有幾個[]並列,這個方法僅僅脫去最右邊的[]以後剩下的內容就做爲這個方法的返回值。爲何返回值類型是Type?

String[] p1 經過getComponentType()返回以後,脫去最右邊的[]以後,剩餘的類型是String。所以對這個參數的返回類型是Class。

*E[]  p2 經過getComponentType()返回以後,脫去最右邊的[]以後,剩餘的類型是E。所以對這個參數的返回類型是TypeVariable。

ArrayList[] p3 經過getComponentType()返回以後,脫去最右邊的[]以後,剩餘的類型是ArrayList。所以對這個參數的返回類型是ParameterizedType。

E[][] p4(){} 經過getComponentType()返回以後,脫去最右邊的[]以後,剩餘的類型是E[]。所以對這個參數的返回類型是GenericArrayType。

TypeVariable 接口類型的含義 

表示類型參數或者又叫作類型變量。好比:void method(E e){}中的E就是類型變量 獲取類型變量的泛型限定的上邊界的類型 源碼聲明:Type[] getActualTypeArguments();

【注意】這裏面僅僅是上邊界。緣由就是類型變量在定義的時候只能使用extends進行(多)邊界限定。不能使用super,不然編譯沒法經過。同時extends給出的都是類型變量的上邊界。

爲何是返回類型是數組?由於類型變量能夠經過&進行多個上邊界限定,所以上邊界有多個,所以返回值類型是數組類型[ ]。

例以下面的方法: public static & Cloneable&Serializable> E methodVI(E e){…} E的第一個上邊界是Map,是ParameterizedType類型 E的第二個上邊界是Cloneable,是Class類型 所以,爲統一,返回值的數組的元素類型就是Type

WildcardType接口類型的含義

表示通配符類型的表達式。 好比 void printColl(ArrayListal); 中的 ? extends Number

【注意】根據上面API的註釋提示:現階段通配符表達式僅僅接受一個上邊界或者下邊界,這個和定義類型變量時候能夠指定多個上邊界是不同。可是API說了,爲了保持擴展性,這裏返回值類型寫成了數組形式。實際上如今返回的數組的大小就是1。

獲取通配符表達式對象的泛型限定的上邊界的類 源碼聲明:Type[] getUpperBounds(); 【注意】上面說了,現階段返回的Type[ ]中的數組大小就是1個。寫成Type[ ]是爲了語言的升級而進行的擴展。

public static voidprintColl(ArrayList> al){}

通配符表達式是:? extendsArrayList,這樣 extends後面是?的上邊界,這個上邊界是ParameterizedType類型。

public static voidprintColl(ArrayList al){}

通配符表達式是:? extends E,這樣 extends後面是?的上邊界,這個上邊界是TypeVariable類型

public static voidprintColl(ArrayList al){}

通配符表達式是:? extends E[],這樣 extends後面是?的上邊界,這個上邊界是GenericArrayType類型

public static voidprintColl(ArrayList al){}

通配符表達式是:? extends Number,這樣 extends後面是?的上邊界,這個上邊界是Class類型 最終統一成Type做爲數組的元素類型。

Type及其子接口的來歷

一. 泛型出現以前的類型

沒有泛型的時候,只有所謂的原始類型。此時,全部的原始類型都經過字節碼文件類Class類進行抽象。Class類的一個具體對象就表明一個指定的原始類型。

二. 泛型出現以後的類型

泛型出現以後,擴充了數據類型。從只有原始類型擴充了參數化類型、類型變量類型、泛型限定的的參數化類型 (含通配符+通配符限定表達式)、泛型數組類型。

三. 與泛型有關的類型不能和原始類型統一到Class的緣由

[1]. 【產生泛型擦除的緣由】

原本新產生的類型+原始類型都應該統一成各自的字節碼文件類型對象。可是因爲泛型不是最初Java中的成分。若是真的加入了泛型,涉及到JVM指令集的修改,這是很是致命的。

[2]. 【Java中如何引入泛型】

爲了使用泛型的優點又不真正引入泛型,Java採用泛型擦除的機制來引入泛型。Java中的泛型僅僅是給編譯器javac使用的,確保數據的安全性和免去強制類型轉換的麻煩。可是,一旦編譯完成,全部的和泛型有關的類型所有擦除。

[3]. 【Class不能表達與泛型有關的類型】

所以,與泛型有關的參數化類型、類型變量類型、泛型限定的的參數化類型 (含通配符+通配符限定表達式)、泛型數組類型這些類型所有被打回原形,在字節碼文件中所有都是泛型被擦除後的原始類型,並不存在和自身類型一致的字節碼文件。因此和泛型相關的新擴充進來的類型不能被統一到Class類中。

[4]. 與泛型有關的類型在Java中的表示

爲了經過反射操做這些類型以迎合實際開發的須要,Java就新增了ParameterizedType,GenericArrayType,TypeVariable 和WildcardType幾種類型來表明不能被歸一到Class類中的類型可是又和原始類型齊名的類型。

[5]. Type的引入:統一與泛型有關的類型和原始類型Class

【引入Type的緣由】爲了程序的擴展性,最終引入了Type接口做爲Class,ParameterizedType,GenericArrayType,TypeVariable和WildcardType這幾種類型的總的父接口。這樣實現了Type類型參數接受以上五種子類的實參或者返回值類型就是Type類型的參數。

【Type接口中沒有方法的緣由】從上面看到,Type的出現僅僅起到了經過多態來達到程序擴展性提升的做用,沒有其餘的做用。所以Type接口的源碼中沒有任何方法。

相關文章
相關標籤/搜索