Retrofit完全解析(三):Type

Object跟Class可跳過

Object
Object是class層次結構的根(Java中萬物皆對象)。Object是所有class的超類(包括Class類)。 所有對象,包括數組,實現Object類的(hashCode、equals、clone、toString、notify..)方法。

Class

  • class的實例Class代表java程序中正在運行的classes和interfaces。
  • enum和annotation也是一種interface。
    每個數組也屬於一個class,反射爲共享數據類型、大小的Class對象。
  • 原始Java類型(boolean byte char short int long float double)關鍵字void也可以表示爲Class對象。
  • Class沒有公開的構造函數,相反,Class 對象是在加載類時由 Java 虛擬機通過調用類加載器中的 defineClass 方法自動構造的。
  • Class.class也是一種class。
  • 每個class都有一個相應的Class對象。當類加載器夾在.class文件的時候就會自動創建對應的Class對象,用於表示這個類的類型信息。
  • Class用來表示class的信息:包命、父類、接口、字段、方法、構造器、註解等。反射中常利用這些信息,可以對於任意一個對象,都能夠調用它的任意一個方法,可以於運行時加載、探知、使用編譯期間完全未知的classes,生成其對象實體、或對其fields設值、或喚起其methods。
  • Class實現了Type空接口,Class爲原始類型(raw types)

GenericDeclaration

  • 註解:A common interface for all entities that declare type variables.
  • 中文:所有聲明類型變量的實體的通用接口。
  • 該接口用來定義哪些對象上是可以聲明(定義)範型變量。
  • 目前實現GenericDeclaration接口的類包括Class, Method, Constructor,也就是說只能在這幾種對象上進行範型變量的聲明(定義)。GenericDeclaration的接口方法getTypeParameters用來逐個獲取該GenericDeclaration的範型變量聲明。

初識Type

Type

  • 註解:Type is the common superinterface for all types in the Java programming language. These include raw types, parameterized types, array types, type variables and primitive types.
  • 中文:Type是Java編程語言中所有Type的共同超級接口。 這些包括原始類型(raw types對應Class)、參數化類型(parameterized types對應ParameterizedType)、 數組類型(array types對應GenericArrayType)、 類型變量(type variables對應TypeVariable)和基本類型(primitive types對應Class)。
  • 子接口:ParameterizedType, TypeVariable, GenericArrayType, WildcardType。
  • 實現類:Class(原始類型: raw types)。

Type四大子接口

ParameterizedType (Collection<String>)(參數話類型)

類註解:參數化類型在第一次由反射方法需要時創建,當參數化類型p被創建時,p實例化的通用類型聲明被解析,並且遞歸地創建p的所有類型參數。 重複創建參數化類型不起作用。實現此接口的類的實例必須實現equals()方法,等同於任何兩個實例共享同一通用類型聲明並具有相等類型參數。

ParameterizedType表示參數化類型,例如Collection<String>

方法

  1. Type getRawType():
    註解:返回聲明此類型的類或者接口對象
    俗解:返回承載該泛型信息的對象, 如上面那個Collection<String>承載範型信息的對象是Collection

  2. Type[] getActualTypeArguments():
    註解:返回表示此類型的實際類型參數的類型對象數組。
    俗解:返回實際泛型類型列表, 如Map<String, String> map實際範型列表中有兩個元素, 都是String

  3. Type getOwnerType():
    註解:返回(本身Type的)父Type對象,比如:如果本身Type是O<T>.I<S>則返回O<T>,如果此類型是頂級類型,則返回null。
    俗解:返回擁有者(主人).(上面那兩個最常用)

public class ParameterizedTypeTest {
    Map<String, String> map;
    public static void main(String[] args) throws Exception {
        Field f = TestType.class.getDeclaredField("map");
        System.out.println(f.getGenericType());                               // java.util.Map<java.lang.String, java.lang.String>
        System.out.println(f.getGenericType() instanceof ParameterizedType);  // true
        ParameterizedType pType = (ParameterizedType) f.getGenericType();
        System.out.println(pType.getRawType());                               // interface java.util.Map
        for (Type type : pType.getActualTypeArguments()) {
            System.out.println(type);                                         // 打印兩遍: class java.lang.String
        }
        System.out.println(pType.getOwnerType());                             // null
    }
}

舉個getOwnerType()的例子:

public static void main(String[] args) throws Exception {
    Method method = new Test().getClass().getMethod("applyMethod",Map.Entry.class);
    Type[] types = method.getGenericParameterTypes();
    ParameterizedType pType = (ParameterizedType)types[0];
    System.out.println(pType.getOwnerType());//打印結果是interface java.util.Map

}

public static <T,U> void applyMethod(Map.Entry<T,U> mapEntry){

}

TypeVariable (<T>)(類型變量)

  • public interface TypeVariable<D extends GenericDeclaration> extends Type {...}
  • TypeVariable中的D是extends GenericDeclaration的,用來通過範型變量反向獲取擁有這個變量的GenericDeclaration。

方法

  1. Type[] getBounds():
    註解:返回此類型變量的上邊界的Type數組(可能有多個),如果上限沒有顯示聲明,則上限爲Object。如果上限是ParameterizedType或者TypeVariable,繼續創建,如果不是——則中斷。
    俗解:獲取類型變量的上邊界, 若未明確聲明上邊界則默認爲Object
  2. D getGenericDeclaration():
    註解:返回表示聲明此類型變量的通用聲明的GenericDeclaration對象。返回爲此類型變量聲明的通用聲明。(類似ParameterizedType的getRawType)
    俗解:獲取聲明該類型變量實體
  3. String getName():
    註解:返回此類型變量的名稱,如同源代碼中出現的。(如上文中的T)
    俗解:獲取在源碼中定義時的名字
注意
類型變量在定義的時候只能使用extends進行(多)邊界限定, 不能用super(奇怪的現象,望告知)。
爲什麼邊界是一個數組? 因爲類型變量可以通過&進行多個上邊界限定,因此上邊界有多個
public class TestType <K extends Comparable & Serializable, V> {
    K key;
    V value;
    public static void main(String[] args) throws Exception {
        // 獲取字段的類型
        Field fk = TestType.class.getDeclaredField("key");
        Field fv = TestType.class.getDeclaredField("value");
        Assert.that(fk.getGenericType() instanceof TypeVariable, "必須爲TypeVariable類型");
        Assert.that(fv.getGenericType() instanceof TypeVariable, "必須爲TypeVariable類型");
        TypeVariable keyType = (TypeVariable)fk.getGenericType();
        TypeVariable valueType = (TypeVariable)fv.getGenericType();
        // getName 方法
        System.out.println(keyType.getName());                 // K
        System.out.println(valueType.getName());               // V
        // getGenericDeclaration 方法
        System.out.println(keyType.getGenericDeclaration());   // class com.test.TestType
        System.out.println(valueType.getGenericDeclaration()); // class com.test.TestType
        // getBounds 方法
        System.out.println("K 的上界:");                        // 有兩個
        for (Type type : keyType.getBounds()) {                // interface java.lang.Comparable
            System.out.println(type);                          // interface java.io.Serializable
        }
        System.out.println("V 的上界:");                        // 沒明確聲明上界的, 默認上界是 Object
        for (Type type : valueType.getBounds()) {              // class java.lang.Object
            System.out.println(type);
        }
    }
}

GenericArrayType(通用數組類型)

註解:GenericArrayType 表示一種數組類型,其組件類型爲參數化類型或類型變量。
俗解:範型數組,組成數組的元素中有範型則實現了該接口; 它的組成元素是ParameterizedType或TypeVariable類型,它只有一個方法:

方法

  1. Type getGenericComponentType():
    註解:返回表示此數組的組件類型的Type對象,此方法創建數組的組件類型.
    俗解:返回數組的組成對象, 即被JVM編譯後實際的對象
    public static void main(String[] args) {
        new GenericArrayTypeTest(); 
        Method method = Test.class.getDeclaredMethods()[0];
        Type[] types = method.getGenericParameterTypes();
        for (Type type : types) {
            if (type instanceof GenericArrayType) {
                GenericArrayType arrayType = (GenericArrayType) type;
                System.out.println(type.getTypeName());
                Type anyType = arrayType.getGenericComponentType();
                printType(anyType);
            }
        }
    }

    public static void printType(Type type){
        String printStr = "";
        if (type instanceof GenericArrayType) {
            printStr  = "GenericArrayType";
        }else if(type instanceof ParameterizedType){
            printStr = "ParameterizedType";
        }else if(type instanceof TypeVariable){
            printStr = "TypeVariable";
        }else if(type instanceof WildcardType){
            printStr = "WildcardType";
        }else if(type instanceof Class){
            printStr = "Class";
        }else{
            printStr = "UnKnown";
        }
        System.out.println(type.getTypeName() +" :::: "+ printStr);
    }

    class Test<T>{
        // List<String>[] pTypeArr > getGenericComponentType > java.util.List<java.lang.String> 爲 ParameterizedType
        // T[] vTypeArr > getGenericComponentType > T 爲 TypeVariable
        public void show(List<String>[] pTypeArr,T[] vTypeArr,List<String> list,String[] strings,int[] ints){}
    }

WildcardType(通配符類型)

註解:WildcardType 表示一個通配符類型表達式,如 ?、? extends Number 或 ? super Integer。

方法

  1. Type[] getUpperBounds();
    註解:返回表示此類型上限的類型數組。 默認上限是Object。
  2. Type[] getLowerBounds();
    註解:返回表示此類型變量的下限的Type對象的數組。 注意,如果沒有明確聲明下界,下界是null的類型。 在這種情況下,返回零長度數組。

    注意:現階段通配符只接受一個上邊界或下邊界, 返回數組是爲了以後的擴展, 實際上現在返回的數組的大小是1

public class TestType {
    private List<? extends Number> a;  // // a沒有下界, 取下界會拋出ArrayIndexOutOfBoundsException
    private List<? super String> b;
    public static void main(String[] args) throws Exception {
        Field fieldA = TestType.class.getDeclaredField("a");
        Field fieldB = TestType.class.getDeclaredField("b");
        // 先拿到範型類型
        Assert.that(fieldA.getGenericType() instanceof ParameterizedType, "");
        Assert.that(fieldB.getGenericType() instanceof ParameterizedType, "");
        ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
        ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
        // 再從範型裏拿到通配符類型
        Assert.that(pTypeA.getActualTypeArguments()[0] instanceof WildcardType, "");
        Assert.that(pTypeB.getActualTypeArguments()[0] instanceof WildcardType, "");
        WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
        WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
        // 方法測試
        System.out.println(wTypeA.getUpperBounds()[0]);   // class java.lang.Number
        System.out.println(wTypeB.getLowerBounds()[0]);   // class java.lang.String
        // 看看通配符類型到底是什麼, 打印結果爲: ? extends java.lang.Number
        System.out.println(wTypeA);
    }
}

總結

之前有誤,在此更正:

四類Type: ParameterizedType TypeVariable GenericArrayType WildcardType
示例: List<String>、List<T> T、T extends Number Class<T>[]、Class<?>[] ?、? extends Number 或 ? super
注意事項: getActualTypeArguments獲取的Tyep不是TypeVariable就是WildcardType 只能使用extends進行(多)邊界限定, 不能用super. Class[]、List[]、int[]、String[] 爲 Class

小結:

  • ParameterizedType的getActualTypeArguments獲取的Tyep不是TypeVariable就是WildcardType
  • GenericArrayType的getGenericComponentType不是ParameterizedType就是TypeVariable
  • 包含泛型的變量類型纔會是四大Type,不然則爲Class
  • 四大Type類型 instanceof Class均爲false
  • 然而有些Type instanceof Class爲true:
    ParameterizedType 的getRawType、getActualTypeArguments、getOwnerType;TypeVariable的getBounds;WildcardType的getUpperBounds、getLowerBounds他們獲取的Type中如果不包含泛型,則均爲Class類型

綜上所屬,Java中所有Type對象:
1. Type對象 instanceof Object均爲true
2. Type對象包含泛型 instanceof Classs 爲false,爲四大Type之一
3. Type對象不包含泛型 instanceof Classs 爲true,不是四大Type,而是接口Type類型。

    class Test<T>{
        // List<String> 爲 ParameterizedType

        // T 爲 TypeVariable

        // Class<T>[] 爲 GenericArrayType
        // Class<?>[] 爲 GenericArrayType  ==> ? 爲 WildcardType

        // List<String>[] pTypeArr > getGenericComponentType > java.util.List<java.lang.String> 爲 ParameterizedType
        // T[] vTypeArr > getGenericComponentType > T 爲 TypeVariable

        // ? 爲 WildcardType
        // Class[]、List[]、int[]、String[]、Class、List、String、int 爲 Class

        // Type要麼是四大Type 要麼爲Class

        public void show(List[] pTypeArr,T[] vTypeArr,List<String> list,String[] strings,Class[] cls,int[] ints,Set<?> set,T t){}
    }

參考文章:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章