天天看點

Java類型Api初探

前言

kotlin語言中大量使用泛型相關文法,對于比較抽象的類和函數如果認識僅僅停留在java 實體上,就不能很好的學習kotlin文法的精髓。協程以及compose中泛型相關api比比皆是。不了解java 類型,就不能學好kotlin和compose

​​秒懂java類型入口​​

Java 類型參數 說明 示例
Type 所有類型的父類型 -
TypeVariable 類型參數 T t
ParameterizedType 參數化類型 List < T >
GenericArrayType 數組類型 T[ ]
WildcardType 通配符類型 <? extends object>、<? super object>
Class 所有類的類型 object.class

下面是通過 這個TypeTest.class 泛型類,來了解java Type類型的四個關鍵子類(TypeVariable、ParameterizedType,GenericArrayType ,WildcardType )及子類中提供的核心api

/**
 * author:[email protected]
 * data: 2022/7/8 14:46
 * 泛型類,參數為T 和 V
 * java 1.5 引入泛型,目的是運作時可以動态替換泛型參數的類型{對象,屬性,[方法形參,傳回值]}
 * 泛型實參必須是引用類型 {class,interface,map,int[],set,list}
 * 泛型通配符:
 */
public class TypeTest<T, V extends @Custom Number & Serializable> {
    private Number number;
    public T t;
    public V v;
    public List<T> list = new ArrayList<>();
    public Map<String, T> map = new HashMap<>();

    //GenericArrayType
    public T[] tArray;
    public List<T>[] ltArray;

    public TypeTest testClass;
    public TypeTest<T, Integer> testClass2;

    public Map<? super String, ? extends Number> mapWithWildcard;

    //泛型構造函數,泛型參數為X
    public <X extends Number> TypeTest(X x, T t) {
        number = x;
        this.t = t;
    }

    //泛型方法,泛型參數為Y
    public <Y extends T> void method(Y y) {
        t = y;
    }
}      

無論是在java還是Kotlin亦或者其他Jvm語言中,所有聲明的可以被jvm識别的類型。均是Type類型的直接子類或者間接子類。最佳實踐就是 Retrofit中 CallAdapter.Factory() 響應資料适配,通過 T 進行序列化與反序列化。

Tips: 類型api需要用到反射知識來驗證。

TypeVariable

Api 說明 示例
getGenericType() 擷取屬性類型 V TypeTest.class.getField(“v”).getGenericType()
getBounds() 擷取類型變量上界 Arrays.asList(typeVariable.getBounds())
getGenericDeclaration() 擷取類型變量聲明宿主 TypeTest typeVariable.getGenericDeclaration()
//通過反射擷取 類型參數 public V v;
  private static void mockTypeVariable() {
        try {
            System.out.println("****************************TypeVariable************************");
            Field v = TypeTest.class.getField("v");
            TypeVariable typeVariable = (TypeVariable) v.getGenericType();//擷取屬性類型 V
            System.out.println("TypeVariable1:" + typeVariable);
             //擷取類型變量上界,java類中類型可以有多個上界
            System.out.println("TypeVariable2:" + Arrays.asList(typeVariable.getBounds()));
             //擷取類型變量聲明載體
            System.out.println("TypeVariable3:" + typeVariable.getGenericDeclaration());          
            //1.8 AnnotatedType: 如果這個這個泛型參數類型的上界用注解标記了,我們可以通過它拿到相應的注解
            AnnotatedType[] annotatedTypes = typeVariable.getAnnotatedBounds();
            System.out.println("TypeVariable4:" + Arrays.asList(annotatedTypes) + " : " +
                    Arrays.asList(annotatedTypes[0].getAnnotations()));
            System.out.println("TypeVariable5:" + typeVariable.getName());
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }      

ParameterizedType

Api 說明 示例 結果
getActualTypeArguments() 擷取參數類型清單 (ParameterizedType)xx.getActualTypeArguments() [class java.lang.String, T]
getRawType() 參數原始類型 - interface java.util.Map
getOwnerType 參數父類型 - null(因為Map沒有外部類,是以為null)
//擷取 List<T> list、 Map<String, T> map
 private static void mockParameterizedType() {
        try {
            //List<T> list
            Field list = TypeTest.class.getField("list");
            //List<T>
            Type genericType1 = list.getGenericType();
            System.out.println("參數類型1:" + genericType1.getTypeName()); //參數類型1:java.util.List<T>

            // Map<String, T> map = new HashMap<>();
            Field map = TypeTest.class.getField("map");
            Type genericType2 = map.getGenericType();
            System.out.println("參數類型2:" + genericType2.getTypeName());//參數類型2:java.util.Map<java.lang.String, T>

            if (genericType2 instanceof ParameterizedType) {
                ParameterizedType pType = (ParameterizedType) genericType2;
                Type[] types = pType.getActualTypeArguments();
                System.out.println("參數類型清單:" + Arrays.asList(types));//參數類型清單:[class java.lang.String, T]
                System.out.println("參數原始類型:" + pType.getRawType());//參數原始類型:interface java.util.Map
                System.out.println("參數父類類型:" + pType.getOwnerType());//參數父類類型:null,因為Map沒有外部類,是以為null
            }
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }      

GenericArrayType

//擷取 public T[] tArray;
    private static void mockGenericArrayType() {
        try {
            System.out.println("**********************GenericArrayType*********************");
            Field tArray = TypeTest.class.getField("tArray");
            System.out.println("數組參數類型1:" + tArray.getGenericType());
            Field ltArray = TypeTest.class.getField("ltArray");
            System.out.println("數組參數類型2:" + ltArray.getGenericType());//數組參數類型2:java.util.List<T>[]
            if (tArray.getGenericType() instanceof GenericArrayType) {
                GenericArrayType arrayType = (GenericArrayType) tArray.getGenericType();
                System.out.println("數組參數類型3:" + arrayType.getGenericComponentType());//數組參數類型3:T
            }
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }      

WildcardType

Api 說明 示例
getLowerBounds() 擷取下界 low = [class java.lang.String]、upper=[class java.lang.Object]
getUpperBounds() 擷取上界 low=[ ]、upper=class java.lang.Number
//擷取 public Map<? super String, ? extends Number> mapWithWildcard;
    private static void mockWildcardType() {
        //WildcardType
        try {
            Field mapWithWildcard = TypeTest.class.getField("mapWithWildcard");
            Type wild = mapWithWildcard.getGenericType();//先擷取屬性的泛型類型 Map<? super String, ? extends Number>
            if (wild instanceof ParameterizedType) {
                ParameterizedType pType = (ParameterizedType) wild;
                Type[] actualTypes = pType.getActualTypeArguments();//擷取<>裡面的參數變量 ? super String, ? extends Number
                System.out.println("WildcardType1:" + Arrays.asList(actualTypes));
                WildcardType first = (WildcardType) actualTypes[0];//? super java.lang.String
                WildcardType second = (WildcardType) actualTypes[1];//? extends java.lang.Number
                System.out.println("WildcardType2: lower:" + Arrays.asList(first.getLowerBounds()) + "  upper:" + Arrays.asList(first.getUpperBounds()));//WildcardType2: lower:[class java.lang.String]  upper:[class java.lang.Object]
                System.out.println("WildcardType3: lower:" + Arrays.asList(second.getLowerBounds()) + "  upper:" + Arrays.asList(second.getUpperBounds()));//WildcardType3: lower:[]  upper:[class java.lang.Number]
            }
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }      

引用位址