前言
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);
}
}