程序员

Android 开发也要掌握的Java知识 - Java 泛型擦

2020-07-28  本文已影响0人  进击的包籽

如果需要看泛型使用Java泛型

1.什么是泛型擦除

2.编译期如何擦除泛型:

1.检查泛型类型,获取目标类型
2.擦除类型变量,替换为限定类型
2.1如果泛型类型的类型变量没有限定,比如<T>,就替换为Object类型为原始类型
2.2如果类型变量是<T extends xxxCalss>,就替换为xxxClass类型为原始类型
2.3如果多个限定<T extends xClass1 & XClass2>,就用第一个xClass1类型为原始类型
3.必要的时候插入类型转换来保存类型安全
4.生成桥接方法,在扩展时保持多态性

3.泛型擦除也会有副作用

1.泛型擦除后替换为Object类型,所以不能传基本数据类型,比如List不能写int类型(List<int>)
2.不能使用instanceof来判断类型,因为是Object嘛
3.类不能声明静态的成员变量,因为泛型参数要创建对象时就确定
等等其他

4.这里放黑马教程的截图,可以在哔哩哔哩上免费观看

无限制类型擦除.png 有限制类型擦除.png 擦除方法中类型定义的参数.png 桥接方法.png

5.验证泛型擦除

5.1用反射查看
public class Test<T extends Number> {
    T t;
 
    public T getT() {
        return t;
    }
 
    public void setT(T t) {
        this.t = t;
    }
 
    public <T extends Number> T show(T t) {
        return t;
    }
}
 
 
/*----------------------------------------------------------*/
 
public class TestObject<T> {
    T t;
 
    public T getT() {
        return t;
    }
 
    public void setT(T t) {
        this.t = t;
    }
 
    public <T> T show(T t){
        return t;
    }
}
 
 
/*----------------------------------------------------------*/

//利用反射,获取Test类的类对象
Test<Integer> test = new Test<>();
Class<? extends Test> clazz = test.getClass();
//获取成员变量
Field[] testField = clazz.getDeclaredFields();
for (Field field : testField) {
    Log.d(TAG, field.getName() + " : " + field.getType().getSimpleName());
}
Log.d(TAG, "-----------------------------------");
//成员方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
    Log.d(TAG, method.getName() + " : " + method.getReturnType().getSimpleName());
}


Log.d(TAG, "-----------------------------------");


TestObject<Integer> testObject = new TestObject<>();
Class<? extends TestObject> clz = testObject.getClass();
//获取成员变量
Field[] testObjectField = clz.getDeclaredFields();
for (Field field : testObjectField) {
    Log.d(TAG, field.getName() + " : " + field.getType().getSimpleName());
}
Log.d(TAG, "-----------------------------------");
//成员方法
Method[] objectMethods = clz.getMethods();
for (Method method : objectMethods) {
    Log.d(TAG, method.getName() + " : " + method.getReturnType().getSimpleName());
}
泛型有限制擦除.png 泛型无限制擦除.png
5.2用字节码查看

6.验证泛型桥接

6.1用反射查看桥接方法
public interface Info<T> {
    T info(T t);
}
 
public class InfoImpl implements Info<Integer> {
    @Override
    public Integer info(Integer integer) {
        return integer;
    }
}
 
/*----------------------------------------------------------*/

InfoImpl info = new InfoImpl();
Class<InfoImpl> infoClazz = InfoImpl.class;
//获取成员变量
Field[] infoFields = infoClazz.getDeclaredFields();
for (Field field : infoFields) {
    Log.d(TAG, field.getName() + " : " + field.getType().getSimpleName());
}
Log.d(TAG, "-----------------------------------");
//成员方法
Method[] infoMethods = infoClazz.getMethods();
for (Method method : infoMethods) {
    Log.d(TAG, method.getName() + " : " + method.getReturnType().getSimpleName());
}
泛型桥接.png
6.2用字节码查看桥接方法
字节码查看桥接方法

7.参考文章

Java中的泛型擦除
哔哩哔哩视频

如果有写的不对,希望大家帮忙指出错误,谢谢!

上一篇 下一篇

猜你喜欢

热点阅读