Spring 泛型處理

一直不懂發表於2020-09-23

Java 泛型基礎

• 泛型型別

  • 泛型型別是在型別上引數化的泛型類或介面

• 泛型使用場景

  • 編譯時強型別檢查
  • 避免型別強轉
  • 實現通用演算法

Java 泛型基礎

泛型型別擦寫

泛型被引入到 Java 語言中,以便在編譯時提供更嚴格的型別檢查並支援泛型程式設計。型別擦除確保不會為引數化型別建立新類;因此,泛型不會產生執行時開銷。為了實現泛型,編譯器將型別擦除應用於:
• 將泛型型別中的所有型別引數替換為其邊界,如果型別引數是無邊界的,則將其替換為
“Object”。因此,生成的位元組碼只包含普通類、介面和方法。
• 必要時插入型別轉換以保持型別安全。
• 生成橋方法以保留擴充套件泛型型別中的多型性。

public class GenericDemo {

    public static void main(String[] args) {
        // Java 7 Diamond 語法
        Collection<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("World");
        // 編譯時錯誤
        // list.add(1);

        // 泛型擦寫
        Collection temp = list;
        // 編譯通過
        temp.add(1);

        System.out.println(list);
    }
}

Java 5 型別介面

• Java 5 型別介面 - java.lang.reflect.Type

派生類或介面說明
java.lang.ClassJava 類 API,如 java.lang.String
java.lang.reflect.GenericArrayType泛型陣列型別
java.lang.reflect.ParameterizedType泛型引數型別
java.lang.reflect.TypeVariable泛型型別變數,如 Collection 中的 E
java.lang.reflect.WildcardType泛型通配型別

• Java 泛型反射 API

型別API
泛型資訊(Generics Info)java.lang.Class#getGenericInfo()
泛型引數(Parameters)java.lang.reflect.ParameterizedType
泛型父類(Super Classes)java.lang.Class#getGenericSuperclass()
泛型介面(Interfaces)java.lang.Class#getGenericInterfaces()
泛型宣告(Generics Declaration)java.lang.reflect.GenericDeclaration

Spring 泛型型別輔助類

核心 API - org.springframework.core.GenericTypeResolver
• 版本支援:[2.5.2 , )
• 處理型別相關(Type)相關方法

  • resolveReturnType
  • resolveType

• 處理泛型引數型別(ParameterizedType)相關方法

  • resolveReturnTypeArgument
  • resolveTypeArgument
  • resolveTypeArguments

• 處理泛型型別變數(TypeVariable)相關方法

  • getTypeVariableMap
class StringList extends ArrayList<String> { // 泛型引數具體化(位元組碼有記錄)
}

/**
 * {@link GenericTypeResolver} 示例
 */
public class GenericTypeResolverDemo {

    public static void main(String[] args) throws NoSuchMethodException {

        // String 是 Comparable<String> 具體化
        displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, Comparable.class, "getString");

        // ArrayList<Object> 是 List 泛型引數型別的具體化
        displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, List.class, "getList");

        // StringList 也是 List 泛型引數型別的具體化
        displayReturnTypeGenericInfo(GenericTypeResolverDemo.class, List.class, "getStringList");

        // 具備 ParameterizedType 返回,否則 null

        // TypeVariable
        Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(StringList.class);
        System.out.println(typeVariableMap);
    }


    public static StringList getStringList() {
        return null;
    }

    public static ArrayList<Object> getList() { // 泛型引數型別具體化
        return null;
    }

    public static String getString() {
        return null;
    }

    private static void displayReturnTypeGenericInfo(Class<?> containingClass, Class<?> genericIfc, String methodName, Class... argumentTypes) throws NoSuchMethodException {
        Method method = containingClass.getMethod(methodName, argumentTypes);

        // 宣告類 GenericTypeResolverDemo.class
        Class<?> returnType = resolveReturnType(method, containingClass);

        // 常規類作為方法返回值
        System.out.printf("GenericTypeResolver.resolveReturnType(%s,%s) = %s\n", methodName, containingClass.getSimpleName(), returnType);
        // 常規型別不具備泛型引數型別 List<E>
        Class<?> returnTypeArgument = resolveReturnTypeArgument(method, genericIfc);
        System.out.printf("GenericTypeResolver.resolveReturnTypeArgument(%s,%s) = %s\n", methodName, containingClass.getSimpleName(), returnTypeArgument);

    }

}

在這裡插入圖片描述

Spring 泛型集合型別輔助類

核心 API - org.springframework.core.GenericCollectionTypeResolver
• 版本支援:[2.0 , 4.3]
• 替換實現:org.springframework.core.ResolvableType
• 處理 Collection 相關

  • getCollection*Type

• 處理 Map 相關

  • getMapKey*Type
  • getMapValue*Type
/**
 * {@link GenericCollectionTypeResolver} 示例
 */
public class GenericCollectionTypeResolverDemo {

    private static StringList stringList;

    private static List<String> strings;

    public static void main(String[] args) throws Exception {

        // StringList extends ArrayList<String> 具體化
        // getCollectionType 返回具體化泛型引數型別集合的成員型別 = String
        System.out.println(GenericCollectionTypeResolver.getCollectionType(StringList.class));

        System.out.println(GenericCollectionTypeResolver.getCollectionType(ArrayList.class));

        // 獲取欄位
        Field field = GenericCollectionTypeResolverDemo.class.getDeclaredField("stringList");
        System.out.println(GenericCollectionTypeResolver.getCollectionFieldType(field));

        field = GenericCollectionTypeResolverDemo.class.getDeclaredField("strings");
        System.out.println(GenericCollectionTypeResolver.getCollectionFieldType(field));
    }
}

在這裡插入圖片描述

Spring 方法引數封裝

核心 API - org.springframework.core.MethodParameter

• 起始版本:[2.0 , )

• 元資訊

  • 關聯的方法 - Method
  • 關聯的構造器 - Constructor
  • 構造器或方法引數索引 - parameterIndex
  • 構造器或方法引數型別 - parameterType
  • 構造器或方法引數泛型型別 - genericParameterType
  • 構造器或方法引數引數名稱 - parameterName
  • 所在的類 - containingClass

Spring 4.0 泛型優化實現 - ResolvableType

核心 API - org.springframework.core.ResolvableType

• 起始版本:[4.0 , )
• 扮演角色:GenericTypeResolver 和 GenericCollectionTypeResolver 替代者
• 工廠方法:for* 方法
• 轉換方法:as* 方法
• 處理方法:resolve* 方法

/**
 * {@link ResolvableType} Demo
 */
public class ResolvableTypeDemo {

    public static void main(String[] args) {
        // 工廠建立
        // StringList <- ArrayList <- AbstractList <- List <- Collection
        ResolvableType resolvableType = ResolvableType.forClass(StringList.class);

        resolvableType.getSuperType(); // ArrayList
        resolvableType.getSuperType().getSuperType(); // AbstractList

        System.out.println(resolvableType.asCollection().resolve()); // 獲取 Raw Type
        System.out.println(resolvableType.asCollection().resolveGeneric(0)); // 獲取泛型引數型別
        
    }
}

在這裡插入圖片描述

ResolvableType 的侷限性

• 侷限一:ResolvableType 無法處理泛型擦寫
• 侷限二:ResolvableType 無法處理非具體化的 ParameterizedType

面試題

Java 泛型擦寫發生在編譯時還是執行時?
答:執行時

請介紹 Java 5 Type 型別的派生類或介面?
答:
• java.lang.Class
• java.lang.reflect.GenericArrayType
• java.lang.reflect.ParameterizedType
• java.lang.reflect.TypeVariable
• java.lang.reflect.WildcardType

請說明 ResolvableType 的設計優勢?
答:
• 簡化 Java 5 Type API 開發,遮蔽複雜 API 的運用,如 ParameterizedType
• 不變性設計(Immutability)
• Fluent API 設計(Builder 模式),鏈式(流式)程式設計

相關文章