泛型 - Type

Java泛型採用類型擦除實現,類型編譯時被擦除爲Object,不兼容基本類型。類型擦除的實現方案主要考慮後向兼容,泛型類型簽名信息特定場景下反射可獲取

泛型類型擦除的好處:
1.運行時內存負擔小,List和List<String>是一種類型(編譯後List和List<String>都是List)
2.兼容性好,Java1.5才推出泛型,它兼容之前的版本

泛型類型擦除的壞處:
1.基本類型無法作爲泛型實參
2.泛型類型無法用作方法重載,編譯後List<Integer>和List<String>都是List
3.泛型類型無法當作真實類型使用    

static <T> void genericMethod(T t){
        T newInstance = new T(); // (no)
        T[] array = new T[0];// (no)
        Class c = T.class; //(no)
        List<T> list = new ArrayList<T>();//(ok)
        if(list instanceof List<String>){} //(no)
    }

使用注意
1.靜態方法無法引用類型泛型參數

靜態方法無法引用類型泛型參數(類泛型是類實例化的時候才知道,所以靜態方法無法引用類泛型)
1.錯誤實例
class GenericClass<T> {
      public static T max(T a,T b){}
}
2.正確實例(Java給瞭解決方案,泛型方法)
class GenericClass<T> {
     public static <R> R max(R a,R b){}
}

2.類型強轉的運行時開銷(編譯之後,泛型類型擦除掉了,使用時仍然需要類型強轉)

Type

Type是一個標記接口,沒有任何方法,Type分原始類型和泛型類型,原始類型有Class,泛型類型有ParameterizedType,TypeVariable,GenericArrayType,WildcardType

Type的子類有:
ParameterizedType 參數化類型
TypeVariable 類型變量類型
GenericArrayType 泛型數組類型
WildcardType 通配符類型
Class 原始類型,也是直接子類

與泛型有關的參數化類型、類型變量類型、通配符類型 、泛型數組類型這些類型編譯後全部被打回原形,在字節碼文件中全部都是泛型被擦除後的原始類型,並不存在和自身類型對應的字節碼文件。所以和泛型相關的新擴充進來的類型不能被統一到Class類中。
那麼在運行時是如何獲取到相應的Type的呢,通過字節碼反編譯可以看出,是將泛型簽名信息保存在Signature,如使用javap -verbose TypeWildcardTest反編譯.class,查看泛型簽名

public class TypeWildcardTest<T extends Serializable> {
}

//反編譯後的泛型簽名信息
Signature: #9                           // <T::Ljava/io/Serializable;>Ljava/lang/Object;

Type獲取方法
1.字段泛型類型Type獲取方法:field.getGenericType()
2.方法參數中的Type獲取方法:method.getGenericParameterTypes()
3.方法返回值的Type獲取方法:method.getGenericReturnType()
4.方法定義上的泛型的Type獲取方法:method.getTypeParameters()
5.類定義上的泛型類型獲取方法:
   1).TypeVariableTest.class.getTypeParameters() 或
   2).genericDeclaration.getTypeParameters() //該方式需要通過類中任意方法參數、方法返回值、字段的泛型TypeVariable類型中的getGenericDeclaration()獲取

ParameterizedType
參數化類型,返回值或參數是List<String>或Map<Integer,String>這種帶有泛型的類型

public interface ParameterizedType extends Type {
	//獲取類型內部的參數化類型 比如Map<K,V>裏面的K,V類型
	Type[] getActualTypeArguments();
	// 類的原始類型,一般都是Class
	Type getRawType();
	// 獲取所有者類型(只有內部類纔有所有者,比如Map.Entry他的所有者就是Map),若不是內部類,此處返回null
    	Type getOwnerType();
}
/**
 * List<T>、Map<K,V>帶有泛型的類型就是參數化類型
 * List這種沒有代泛型的類型就不是參數化類型,這個類型是Class
 * ParameterizedType的實現類是ParameterizedTypeImpl
 * 注意ParameterizedType和TypeVariable的區別,List<T>是ParameterizedType,T是TypeVariable
 * @param <T>
 */
class ParameterizedTypeTest<T> {

    public List<T> data;

    public List<String> testParameterizedType(Map<Integer,String> arg){
        return null;
    }

    public static void main(String[] args) throws Exception{
        Method testParameterizedTypeMethod = ParameterizedTypeTest.class.getDeclaredMethod("testParameterizedType", Map.class);
        System.out.println(testParameterizedTypeMethod);//public java.util.List ParameterizedTypeTest.testParameterizedType(java.util.Map)
        //參數類型
        Type[] genericParameterTypes = testParameterizedTypeMethod.getGenericParameterTypes();
        ParameterizedType parameterizedType = (ParameterizedType) genericParameterTypes[0];
        System.out.println("parameterizedType : " + parameterizedType);//parameterizedType : java.util.Map<java.lang.Integer, java.lang.String>
        //也就是泛型有幾個,數組的個數就是幾個,這裏是2個
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        System.out.println("actualTypeArguments[0] : " + actualTypeArguments[0]);//actualTypeArguments[0] : class java.lang.Integer
        System.out.println("actualTypeArguments[1] : " + actualTypeArguments[1]);//actualTypeArguments[1] : class java.lang.String
        //原始類型,就是沒有泛型的類型
        Type rawType = parameterizedType.getRawType();
        System.out.println("rawType : " + rawType);//rawType : interface java.util.Map
        Type ownerType = parameterizedType.getOwnerType();
        System.out.println("ownerType : " + ownerType);//ownerType : null
        //返回值類型
        Type genericReturnType = testParameterizedTypeMethod.getGenericReturnType();
        ParameterizedType parameterizedType2 = (ParameterizedType)genericReturnType;
        System.out.println("parameterizedType2 : " + parameterizedType2);//parameterizedType2 : java.util.List<java.lang.String>
        Type[] actualTypeArguments2 = parameterizedType2.getActualTypeArguments();
        System.out.println("actualTypeArguments2[0] : " + actualTypeArguments2[0]);//actualTypeArguments2[0] : class java.lang.String
        Type rawType2 = parameterizedType2.getRawType();
        System.out.println("rawType2 : " + rawType2);//rawType2 : interface java.util.List
        Type ownerType2 = parameterizedType2.getOwnerType();
        System.out.println("ownerType2 : " + ownerType2);//ownerType2 : null

        //字段類型
        Field dataField = ParameterizedTypeTest.class.getDeclaredField("data");
        Type genericType = dataField.getGenericType();//獲取字段的泛型參數類型
        ParameterizedType parameterizedType3 = (ParameterizedType)genericType;
        System.out.println("parameterizedType3 : " + parameterizedType3);//parameterizedType3 : java.util.List<T>
        Type[] actualTypeArguments3 = parameterizedType3.getActualTypeArguments();
        //actualTypeArguments3[0]是TypeVariable類型
        System.out.println("actualTypeArguments3[0] : " + actualTypeArguments3[0]);//actualTypeArguments3[0] : T
        Type rawType3 = parameterizedType3.getRawType();
        System.out.println("rawType3 : " + rawType3);//rawType3 : interface java.util.List
        Type ownerType3 = parameterizedType3.getOwnerType();
        System.out.println("ownerType3 : " + ownerType3);//ownerType3 : null
    }
}

GenericArrayType
泛型數組類型,返回值或參數是List<String>[]或Map<Integer,String>[]或T[]這種帶有泛型的類型

public interface GenericArrayType extends Type {
	//返回泛型數組中元素的Type類型,即List<String>[] 中的 List<String>
	Type getGenericComponentType();
}
/**
 * List<String>[],T[]都是泛型數組類型,而String[]則不是,String[]屬於Class普通類型
 * GenericArrayType的實現類是ParameterizedTypeImpl
 * @param <T>
 */
class GenericArrayTypeTest<T> {
    public List<String>[] testGenericArrayType(T[] args){
        return null;
    }

    public static void main(String[] args) throws Exception{
        Method testGenericArrayTypeMethod = GenericArrayTypeTest.class.getDeclaredMethod("testGenericArrayType", Object[].class);
        System.out.println(testGenericArrayTypeMethod);
        //參數類型
        Type[] genericParameterTypes = testGenericArrayTypeMethod.getGenericParameterTypes();
        GenericArrayType genericArrayType = (GenericArrayType) genericParameterTypes[0];//獲取第0個參數
        System.out.println("genericArrayType : " + genericArrayType);//genericArrayType : T[]
        Type genericComponentType = genericArrayType.getGenericComponentType();
        System.out.println("genericComponentType : " + genericComponentType);//genericComponentType : T
        //返回值類型
        Type genericReturnType = testGenericArrayTypeMethod.getGenericReturnType();
        GenericArrayType genericArrayType2 = (GenericArrayType) genericReturnType;//獲取返回值類型
        System.out.println("genericArrayType2 : " + genericArrayType2);//genericArrayType2 : java.util.List<java.lang.String>[]
        Type genericComponentType2 = genericArrayType2.getGenericComponentType();
        System.out.println("genericComponentType2 : " + genericComponentType2);//genericComponentType2 : java.util.List<java.lang.String>
    }
}

WildcardType 
泛型表達式類型,返回值或參數是List<? extends Object>或Map<? extends Object,? super Object>這種帶有泛型的類型,通過getActualTypeArguments獲取

public interface WildcardType extends Type {
	//獲得泛型表達式上界(上限) 獲取泛型變量的上邊界(extends) 
	Type[] getUpperBounds();
	//獲得泛型表達式下界(下限) 獲取泛型變量的下邊界(super)
	Type[] getLowerBounds();
}
/**
 * Map<? extends Object,? super String> 和 List<? extends T> 這樣的通配符表達式是泛型表達式類型,
 * 不過需要通過ParameterizedType類型的getActualTypeArguments方法獲取,因爲List<? extends T>等仍然是ParameterizedType類型,只是裏面的泛型 ? extends T 是WildcardType類型
 * WildcardType的實現類是WildcardTypeImpl
 * 類或者方法聲明的泛型上可以使用&(並且)操作符
 * &不能用於?通配符上(因爲通配符不能放在泛型的聲明上),因爲&只能放在泛型的聲明上
 **/
class WildcardTypeTest {

    public Class<?> clazz; //默認<? extends Object>

    /**
     * 方法參數中的Type獲取方法:method.getGenericParameterTypes()
     * 方法返回值的Type獲取方法:method.getGenericReturnType()
     * 方法定義上的泛型的Type獲取方法:method.getTypeParameters()
     * @param arg
     * @param <T>
     * @return
     */
    public <T extends Object & Serializable> List<? extends T> testWildcardType(Map<? extends Object,? super String> arg){
        return null;
    }

    public static void main(String[] args) throws Exception {
        Method testWildcardTypeMethod = WildcardTypeTest.class.getDeclaredMethod("testWildcardType", Map.class);
        //參數類型
        Type[] genericParameterTypes = testWildcardTypeMethod.getGenericParameterTypes();
        ParameterizedType parameterizedType = (ParameterizedType) genericParameterTypes[0];
        System.out.println("parameterizedType : " + parameterizedType);//parameterizedType : java.util.Map<?, ? super java.lang.String>
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        WildcardType wildcardType1 = (WildcardType) actualTypeArguments[0];//獲取Map泛型中的第一個泛型參數
        Type[] upperBounds = wildcardType1.getUpperBounds();
        System.out.println("upperBounds[0] : " + upperBounds[0]);//upperBounds[0] : class java.lang.Object
        Type[] lowerBounds = wildcardType1.getLowerBounds();//空數組
        WildcardType wildcardType2 = (WildcardType) actualTypeArguments[1];
        Type[] upperBounds2 = wildcardType2.getUpperBounds();//空數組
        Type[] lowerBounds2 = wildcardType2.getLowerBounds();
        System.out.println("lowerBounds2[0] : " + lowerBounds2[0]);//lowerBounds2[0] : class java.lang.String
        //返回值類型
        Type genericReturnType = testWildcardTypeMethod.getGenericReturnType();
        ParameterizedType parameterizedType2 = (ParameterizedType) genericReturnType;
        System.out.println("parameterizedType2 : " + parameterizedType2);//parameterizedType2 : java.util.List<? extends T>
        Type[] actualTypeArguments2 = parameterizedType2.getActualTypeArguments();
        WildcardType wildcardType3 = (WildcardType) actualTypeArguments2[0];
        Type[] upperBounds3 = wildcardType3.getUpperBounds();
        //upperBounds3[0]的是TypeVariable類型
        System.out.println("upperBounds3[0] : " + upperBounds3[0]);////upperBounds3[0] : T

        //方法定義上的泛型
        TypeVariable<Method>[] typeParameters = testWildcardTypeMethod.getTypeParameters();
        //<T extends Object & Serializable>是TypeVariable類型
        TypeVariable typeVariable = typeParameters[0];
        String name = typeVariable.getName();
        System.out.println("name : " + name);//name : T
        Type[] bounds = typeVariable.getBounds();
        //<T extends Object & Serializable>中T的上限是Object & Serializable
        //bounds[0]是Object的Type,也就是Class
        //bounds[1]是Serializable的Type,也就是Class
        System.out.println("bounds[0] : " + bounds[0]);//bounds[0] : class java.lang.Object
        System.out.println("bounds[1] : " + bounds[1]);//bounds[1] : interface java.io.Serializable

        //字段
        Field clazzField = WildcardTypeTest.class.getDeclaredField("clazz");
        Type genericType = clazzField.getGenericType();//獲取字段的泛型參數類型
        ParameterizedType parameterizedType4 = (ParameterizedType)genericType;
        System.out.println("parameterizedType4 : " + parameterizedType4);//parameterizedType4 : java.lang.Class<?>
        Type[] actualTypeArguments4 = parameterizedType4.getActualTypeArguments();
        WildcardType wildcardType4 = (WildcardType)actualTypeArguments4[0];
        Type[] upperBounds4 = wildcardType4.getUpperBounds();
        System.out.println("upperBounds4[0] : " + upperBounds4[0]);//upperBounds4[0] : class java.lang.Object
        Type[] lowerBounds4 = wildcardType4.getLowerBounds();//空數組

    }
}

TypeVariable
類型變量,是List<T>中的T,而不是List<T>

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
	//類型對應的上限,默認爲Object  可以有多個
    	Type[] getBounds();
    	//獲取聲明該類型變量實體,也就是TypeVariableTest< T>中的TypeVariableTest
    	D getGenericDeclaration();
    	//獲取類型變量在源碼中定義的名稱;	
   	 String getName();
   	 // JDK8新增的,直接獲取聲明該類型變量實體的類型上下限,
	// 無需通過GenericDeclaration獲取
    	AnnotatedType[] getAnnotatedBounds();
}
/**
 * List<T>、Map<K,V>中的T,K,V等值是TypeVariable
 * TypeVariable的實現類是TypeVariableImpl
 * 類上限定泛型類型變量的上限可以爲多個,必須使用&符號相連接,& 後必須爲接口
 * 類上限定泛型只能是上限extends,不能是下限super
 * 
 * 類定義上的泛型類型獲取方法:
 *  TypeVariableTest.class.getTypeParameters() 或
 *  genericDeclaration.getTypeParameters() //該方式需要通過類中任意方法參數、方法返回值、字段的泛型TypeVariable類型中的getGenericDeclaration()獲取
 * 
 * @param <T> 有類型上限
 * @param <V> 無類型上限,沒有寫上限,默認是Object
 */
class TypeVariableTest<T extends Number & Serializable,V> {

    public Map<T,V> map;

    public T[] array;

    public List<String> testTypeVariable(T arg){
        return null;
    }

    public static void main(String[] args) throws Exception{
        Method testParameterizedTypeMethod = TypeVariableTest.class.getDeclaredMethod("testTypeVariable", Number.class);
        System.out.println(testParameterizedTypeMethod);//public java.util.List TypeVariableTest.testTypeVariable(java.lang.Number)
        //參數類型
        Type[] genericParameterTypes = testParameterizedTypeMethod.getGenericParameterTypes();
        TypeVariable typeVariable = (TypeVariable) genericParameterTypes[0];
        String name = typeVariable.getName();
        System.out.println("name : " + name);//name : T
        Type[] bounds = typeVariable.getBounds();//獲取對應的上限或下限
        //因爲參數arg的類型是泛型T,而泛型T在類上定義有兩個上限,Number和Serializable
        //bounds[0]中的類型是Number,而其Type的實現類是Class
        //bounds[1]中的類型是Serializable,而其Type的實現類是Class
        System.out.println("bounds[0] : " + bounds[0]);//bounds[0] : class java.lang.Number
        System.out.println("bounds[1] : " + bounds[1]);//bounds[1] : interface java.io.Serializable
        GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();//獲取聲明該類型變量實體,也就是TypeVariableTest
        //genericDeclaration是類TypeVariableTest,Class是GenericDeclaration的實現類
        System.out.println("genericDeclaration : " + genericDeclaration);//genericDeclaration : class TypeVariableTest
        TypeVariable<?>[] typeParameters = genericDeclaration.getTypeParameters();//獲取TypeVariableTest類定義的泛型參數
        //typeParameters是指TypeVariableTest上的泛型類型參數,也就是T,V
        String name02 = typeParameters[0].getName();
        System.out.println("name02 : " + name02);//name02 : T
        String name12 = typeParameters[1].getName();
        System.out.println("name12 : " + name12);//name12 : V
        Type[] bounds02 = typeParameters[0].getBounds();//獲取上下限
        //T的上限是Number & Serializable,所以有兩個,都是原始類型Class類型,具體類Number 和 Serializable的Type是Class
        System.out.println("bounds02[0] : " + bounds02[0]);//bounds02[0] : class java.lang.Number
        System.out.println("bounds02[1] : " + bounds02[1]);//bounds02[1] : interface java.io.Serializable
        GenericDeclaration genericDeclaration02 = typeParameters[0].getGenericDeclaration();//這個獲取的還是TypeVariableTest
        Type[] bounds12 = typeParameters[1].getBounds();//獲取上下限
        //V的上限是Object(沒有指定,默認是Object),所以只有一個,也是原始類型Class類型
        System.out.println("bounds12[0] : " + bounds12[0]);//bounds12[0] : class java.lang.Object
        AnnotatedType[] annotatedBounds = typeVariable.getAnnotatedBounds();//直接獲取註解邊界(上下限)
        //typeVariable是參數泛型T,而它的上下限定義在類TypeVariableTest上,也就是Number & Serializable
        //所以annotatedBounds中是兩個上限Number 和 Serializable
        Type type02 = annotatedBounds[0].getType();//原始類型Class,因爲Number是具體類
        System.out.println("type02 : " + type02);//type02 : class java.lang.Number
        Type type12 = annotatedBounds[1].getType();
        System.out.println("type12 : " + type12);//type12 : interface java.io.Serializable

        //返回值類型
        //List<String>沒有TypeVariable類型,只有代泛型T的纔有,如List<T>或List<V>
        Type genericReturnType = testParameterizedTypeMethod.getGenericReturnType();
        ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        //actualTypeArguments[0]對應的是List<String>中的String,而String是具體類型,所以Type是Class
        System.out.println("actualTypeArguments[0] : " + actualTypeArguments[0]);//actualTypeArguments[0] : class java.lang.String

        //字段
        Field mapField = TypeVariableTest.class.getDeclaredField("map");
        Type genericType = mapField.getGenericType();
        ParameterizedType parameterizedType2 = (ParameterizedType) genericType;
        Type[] actualTypeArguments2 = parameterizedType2.getActualTypeArguments();
        //actualTypeArguments2是T,V,也就是TypeVariable
        TypeVariable typeVariable03 = (TypeVariable) actualTypeArguments2[0];//T
        String name03 = typeVariable03.getName();
        System.out.println("name03 : " + name03);//name03 : T
        Type[] bounds3 = typeVariable03.getBounds();
        //T的上限是Number & Serializable,也就是原始類型,所以是Class
        System.out.println("bounds3[0] : " + bounds3[0]);//bounds3[0] : class java.lang.Number
        System.out.println("bounds3[1] : " + bounds3[1]);//bounds3[1] : interface java.io.Serializable
        TypeVariable typeVariable13 = (TypeVariable) actualTypeArguments2[1];//V
        Type[] bounds13 = typeVariable13.getBounds();
        //V的上限是Object,也是原始類型,所以是Class
        System.out.println("bounds13[0] : " + bounds13[0]);//bounds13[0] : class java.lang.Object

        Field arrayField = TypeVariableTest.class.getDeclaredField("array");
        Type genericType2 = arrayField.getGenericType();
        GenericArrayType genericArrayType = (GenericArrayType) genericType2;
        Type genericComponentType = genericArrayType.getGenericComponentType();
        TypeVariable typeVariable2 = (TypeVariable) genericComponentType;//T
        String name4 = typeVariable2.getName();
        System.out.println("name4 : " + name4);//name4 : T
        Type[] bounds4 = typeVariable2.getBounds();
        //T的上下限是 Number & Serializable
        //bounds4[0]和bounds4[1]分別是Number和Serializable的Class
        System.out.println("bounds4[0] : " + bounds4[0]);//bounds4[0] : class java.lang.Number
        System.out.println("bounds4[1] : " + bounds4[1]);//bounds4[1] : interface java.io.Serializable
    }
}

Class
原始/基本類型,如String或Object等具體類型的Type就是Class,Type的直接子類只有一個,也就是Class,代表着類型中的原始類型以及基本類型

/**
 * 原始/基本類型,也就是不帶任何泛型信息的類型,如String,Integer[]的Class
 * Type的直接子類只有一個,也就是Class,代表着類型中的原始類型以及基本類型
 */
class ClassTest {

    public void testClass(String arg){

    }

    public static void main(String[] args) throws Exception{
        Method testClassMethod = ClassTest.class.getDeclaredMethod("testClass", String.class);
        //參數類型
        Type[] genericParameterTypes = testClassMethod.getGenericParameterTypes();
        Class clazz = (Class) genericParameterTypes[0];//Class
        System.out.println("clazz : " + clazz);//clazz : class java.lang.String

        TypeVariable<Class<B>>[] typeParameters = B.class.getTypeParameters();
        TypeVariable typeVariable = typeParameters[0];
        String name = typeVariable.getName();
        System.out.println("name : " + name);//name : T
        Type[] bounds = typeVariable.getBounds();
        //T的默認上限是Object,則Type是Class
        System.out.println("bounds[0] : " + bounds[0]);//bounds[0] : class java.lang.Object
        Class<? super B> superclass = B.class.getSuperclass();//返回直接繼承的父類,不顯示泛型參數
        System.out.println("superclass : " + superclass);//superclass : class ClassTest$A
        Type genericSuperclass = B.class.getGenericSuperclass();//返回直接繼承的父類 顯示泛型參數
        System.out.println("genericSuperclass : " + genericSuperclass);//genericSuperclass : ClassTest$A<T>
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        Type rawType = parameterizedType.getRawType();//原始類型,即A,也就是插除泛型信息的類型
        System.out.println("rawType : " + rawType);//rawType : class ClassTest$A
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        //類型參數是T
        System.out.println("actualTypeArguments[0] : " + actualTypeArguments[0]);//actualTypeArguments[0] : T
        TypeVariable typeVariable2 = (TypeVariable) actualTypeArguments[0];
        String name2 = typeVariable2.getName();
        System.out.println("name2 : " + name2);//name2 : T
        Type[] bounds2 = typeVariable2.getBounds();
        //T的上限默認是Object
        System.out.println("bounds2[0] : " + bounds2[0]);//bounds2[0] : class java.lang.Object
    }

    class A<V> {

    }

    class B<T> extends A<T>{

    }
}

總結
Map<String,? extends T>[]:這裏的Map<String,? extends T>就是ParameterizedType,String就是Class,? entends T就是WildcardType,T就是TypeVariable,整個Map<String,? extends T>[]就是GenericArrayType

參考:
https://blog.csdn.net/f641385712/article/details/88789847

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