重新学习【泛型】

198 阅读2分钟

Java泛型采用类型擦除实现;类型编译时被擦除为Object,不兼容基本数据类型;类型擦除的实现方案主要考虑向后兼容;泛型类型签名信息特定场景下反射可获取;

定义

泛型是JDK 1.5的一项新特性,它的本质是参数化类型 ParameterizedType,即带有类型参数的类型。

泛型的意义

一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码的束缚就会很大。

Java在引入泛型之前,表示可变对象,通常使用Object来实现,但是在进行类型强制转换时存在安全风险。有了泛型后:

  • 编译期间确定类型,保证类型安全,放的是什么,取的也是什么,不用担心抛出ClassCaseException异常。
  • 提升可读性,从编译阶段就显式知道泛型集合、泛型方法等处理的对象类型是什么。
  • 泛型合并了同类型的处理代码,提高了代码的重用率,增加程序的通用灵活性。

泛型的表示

泛型可以定义在类、接口、方法中,分别表示泛型类、泛型接口、泛型方法。

附加的签名信息

class SuperClass<T>{}

class SubClass extends SuperClass<String>{
    public List<Map<String,Integer>> getValue(){
        return null;
    }
}
ParameterizedType superType = (ParameterizedType)SubClass.class.getGenericSuperclass();
for(Type actualTypeArgument : superType.getActualTypeArguments()){
    System.out.println(actualTypeArgument);
}
ParameterizedType methodType = (ParameterizedType)SubClass.class.getMethod("getValue").getGenericReturnType();
for(Type type : methodType.getActualTypeArguments()){
    System.out.println(type);
}

混淆时要保留签名信息

-keepattributes Signature

拓展:使用泛型签名的两个实例

Gson

Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints = gson.fromJson(json, collectionType);

Retrofit

interface GitHubServiceApi{
    @GET("users/{login}")
    Call<User> getUserCallback(@Path("login")String login);
}

拓展:Kotlin反射的实现原理

Kotlin

class HelloWorld

image.png

-keep class kotlin.Metadata {*;}