Java 泛型擦除 学习笔记

文章目录

        • 1.什么是泛型擦除
        • 2.编译期如何擦除泛型:
        • 3.泛型擦除也会有副作用
        • 4.这里放黑马教程的截图,可以在哔哩哔哩上免费观看
        • 5.验证泛型擦除
          • 5.1用反射查看
          • 5.2用字节码查看
        • 6.验证泛型桥接
          • 6.1用反射查看桥接方法
          • 6.2用字节码查看桥接方法
        • 7.参考文章

1.什么是泛型擦除

  • 因为Java 泛型是1.5版本才引入的,为了向下兼容,其实虚拟机是不支持泛型的,Java里面是伪泛型机制
  • Java在编译期就擦除了所有泛型信息,这样Java就不需要产生新的类型到字节码,所有泛型类型最终都是一种类型

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

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

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

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

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

Java 泛型擦除 学习笔记_第1张图片

Java 泛型擦除 学习笔记_第2张图片

Java 泛型擦除 学习笔记_第3张图片

Java 泛型擦除 学习笔记_第4张图片

5.验证泛型擦除

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

//利用反射,获取Test类的类对象
Test test = new Test<>();
Class 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 testObject = new TestObject<>();
Class 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());
}

Java 泛型擦除 学习笔记_第5张图片

Java 泛型擦除 学习笔记_第6张图片

  • 我们可以看到 extends Number,反射拿到的类型就是Number,否则就是Object
5.2用字节码查看
  • Android studio 安装ASM Bytecode Viewer就能查看
    Java 泛型擦除 学习笔记_第7张图片
    Java 泛型擦除 学习笔记_第8张图片
    Java 泛型擦除 学习笔记_第9张图片
    Java 泛型擦除 学习笔记_第10张图片

6.验证泛型桥接

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

InfoImpl info = new InfoImpl();
Class 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());
}

Java 泛型擦除 学习笔记_第11张图片

  • 可以看到info方法有两个
6.2用字节码查看桥接方法

Java 泛型擦除 学习笔记_第12张图片

7.参考文章

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

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

你可能感兴趣的:(Java知识)