类型擦除机制(编译时擦除为Object)
- 使用泛型的时候加上的类型参数,会在编译的时候去掉(在生成的Java字节码中是不包含泛型中的类型信息的)。这个过程就称为类型擦除。
优势
- Java 1.5 才开始引入泛型,兼容性问题,兼容之前的版本
缺陷
- 基本类型无法作为泛型实参(因为编译时被擦除为Object类型),只能用包装类型,装箱开箱有开销
- 泛型类型无法当做真实的类型使用,因为编译后的泛型为Object类型
- 泛型类型无法用方法重载,因为编译后都是List list
public void print(List<Integer> list){ }
public void print(List<String> list){ }
- 静态方法无法引用类泛型参数(可以给静态方法单独加上泛型参数),因为只有类实例化的时候才会知道泛型参数,而静态方法不需要持有类的实例
- 类型强转时的开销(Object强转到对应的类型)
附加的签名信息特定场景下反射可以获取
class SuperClass<T> {
}
class SubClass extends SuperClass<String> {
public List<Map<String, String>> getValue() {
return null;
}
}
public class ATest {
@Test
public void test3() {
Class<? extends SuperClass> aClass1 = new SuperClass<Integer>().getClass();
Class<? extends SuperClass<Integer>> aClass2 = new SuperClass<Integer>() {
}.getClass();
Class<SubClass> aClass3 = SubClass.class;
printType(aClass3);
printType(aClass2);
printType(aClass1);
}
void printType(Class<? extends SuperClass> aClass) {
ParameterizedType genericSuperclass = (ParameterizedType) aClass.getGenericSuperclass();
System.out.println(genericSuperclass.getActualTypeArguments()[0]);
}
}
class SuperClass<T> {
}
class SubClass extends SuperClass<String> {
public List<Map<String, String>> getValue() {
return null;
}
}
public class ATest {
@Test
public void test4() throws NoSuchMethodException {
Class<SubClass> aClass3 = SubClass.class;
ParameterizedType genericSuperclass = (ParameterizedType)aClass3
.getMethod("getValue")
.getGenericReturnType();
System.out.println(genericSuperclass.getActualTypeArguments()[0]);
}
}
Gson中泛型签名的应用
- new TypeToken<List>() { }.getType()
@Test
public void test5() {
Gson gson = new Gson();
User user1 = new User(10, "bob");
User user2 = new User(12, "jack");
ArrayList<User> users = new ArrayList<>();
users.add(user1);
users.add(user2);
String json = gson.toJson(users);
System.out.println(json);
List<User> userList = gson.fromJson(json,
new TypeToken<List<User>>() {
}.getType());
System.out.println(userList);
}
- Gson中的源码
创建子类可以获取到父类的泛型信息,所以需要创建一个匿名子类new TypeToken<List>() { }.getType()
protected TypeToken() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
this.hashCode = type.hashCode();
}
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
泛型混淆,签名问题,混淆后签名找不到了,导致反射后拿不到
- 保留签名信息
-keepattributes Signature - Kotlin中
-keep class kotlin.Metadata {*;}
参考文献