Type及其子接口的來歷
泛型出現以前的類型
沒有泛型的時候,只有原始類型。此時,全部的原始類型都經過字節碼文件類Class類進行抽象。Class類的一個具體對象就表明一個指定的原始類型。html
泛型出現以後的類型
泛型出現以後,擴充了數據類型。從只有原始類型擴充了參數化類型、類型變量類型、限定符類型 、泛型數組類型。java
與泛型有關的類型不能和原始類型統一到Class的緣由
- 產生泛型擦除的緣由
原始類型和新產生的類型都應該統一成各自的字節碼文件類型對象。可是因爲泛型不是最初Java中的成分。若是真的加入了泛型,涉及到JVM指令集的修改,這是很是致命的。數組
- Java中如何引入泛型
爲了使用泛型又不真正引入泛型,Java採用泛型擦除機制來引入泛型。Java中的泛型僅僅是給編譯器javac使用的,確保數據的安全性和免去強制類型轉換的麻煩。可是,一旦編譯完成,全部的和泛型有關的類型所有擦除。安全
- Class不能表達與泛型有關的類型
所以,與泛型有關的參數化類型、類型變量類型、限定符類型 、泛型數組類型這些類型編譯後所有被打回原形,在字節碼文件中所有都是泛型被擦除後的原始類型,並不存在和自身類型對應的字節碼文件。因此和泛型相關的新擴充進來的類型不能被統一到Class類中。url
- 與泛型有關的類型在Java中的表示
爲了經過反射操做這些類型以迎合實際開發的須要,Java就新增了ParameterizedType, TypeVariable<D>, GenericArrayType, WildcardType
幾種類型來表明不能被歸一到Class類中的類型可是又和原始類型齊名的類型。spa
- 引入Type的緣由
爲了程序的擴展性,最終引入了Type接口做爲Class和ParameterizedType, TypeVariable<D>, GenericArrayType, WildcardType
這幾種類型的總的父接口。這樣能夠用Type類型的參數來接受以上五種子類的實參或者返回值類型就是Type類型的參數。統一了與泛型有關的類型和原始類型Class.net
- Type接口中沒有方法的緣由
從上面看到,Type的出現僅僅起到了經過多態來達到程序擴展性提升的做用,沒有其餘的做用。所以Type接口的源碼中沒有任何方法。code
public static void getTypeParameters(){ List<Integer> list = new ArrayList<Integer>(); Map<Integer, String> map = new HashMap<Integer, String>(); System.out.println(Arrays.toString(list.getClass().getTypeParameters())); //[E] System.out.println(Arrays.toString(map.getClass().getTypeParameters())); //[K, V] } /** * 其中最關鍵的差異是本節的變量聲明多了一對大括號 * 變量聲明實際上是建立了一個匿名內部類, 這個類是 HashMap 的子類 * * Java 引入泛型擦除的緣由是避免由於引入泛型而致使運行時建立沒必要要的類。那咱們其實就能夠經過定義類的方式,在 * 類信息中保留泛型信息,從而在運行時得到這些泛型信息 * * 簡而言之,Java 的泛型擦除是有範圍的,即類定義中的泛型是不會被擦除的 * */ public static void getActualTypeArguments(){ // Map<String, Integer> map = new HashMap<String, Integer>() ; Map<String, Integer> map = new HashMap<String, Integer>() {}; Type type = map.getClass().getGenericSuperclass(); ParameterizedType parameterizedType = ParameterizedType.class.cast(type); for (Type typeArgument : parameterizedType.getActualTypeArguments()) { System.out.println(typeArgument.getTypeName()); //java.lang.String, java.lang.Integer } }
參考:htm