【02】Java泛型原理与擦除机制

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

Java泛型原理与擦除机制

1.Java中是如何来处理泛型的?

1.1泛型擦除

1.1.1为什么泛型擦除的时候需要用到桥方法?

(1)使用桥方法是为了保证泛型擦除之后,子类还是能够保证实现接口方法,由桥方法去调用泛型擦除之后的子类方法。

(2)示例代码如下:

(3)桥方法的查看,可以通过字节码查看插件ASM ByteCode Viewer进行查看。具体使用方法将在其他博客展示。

在这里插入图片描述

1.2泛型擦除残留

(1)字节码示例
在这里插入图片描述

(2)上图是泛型擦除后的字节码截图,为什么在字节码文件中还有泛型残留T。
(a)原因是这里看到的其实只是方法的签名和泛型接口定义的格式,这样子,对于分析字节码是有好处的。
(b)这些信息它会存放在类的常量池里面

1.3泛型与反射

1.3.1泛型不是被擦除了吗?那为何还与反射有关?

在这里插入图片描述

(1)原因是擦除,其实是在类的常量池里面保留了泛型的信息。
(2)泛型的信息拿出来之后有什么用?
(a)通过反射拿到具体的类型,在Retrofit中看源码。

1.4Java泛型的原理是什么?什么是泛型擦除机制?

(1)Java的泛型是JDK5新引入的特性,为了向下兼容,虚拟机其实是不支持泛型,所以Java实现的是一种伪泛型机制,也就是说Java在编译期擦除了所有的泛型信息,这样Java就不需要产生新的类型到字节码,所有的泛型类型最终都是一种原始类型,在Java运行时根本就不存在泛型信息。

1.5Java编译器具体是如何控除泛型的?

(1)检查泛型类型,获取目标类型。
(2)擦除类型变量,并替换为限定类型。

(a)如果泛型类型的类型变量没有限定(<T>),则用Object作为原始类型。
(b)如果有限定(<T extends XClass>),则用XClass作为原始类型
(c)如果有多个限定(T extends XClass1&XClass2),则使用第一个边界XClass1作为原始类

(3)在必要时插入类型转换以保持类型安全
(4)生成桥方法以在扩展时保持多态性。

2.使用泛型以及泛型擦除带来的影响

2.1泛型类型变量不能使用基本数据类型

1)比如没有ArrayList<int>,只有ArrayList<Integer>.当类型擦除后,ArrayList的原始类中类的类型变量(T)替换成Object,但Object类型不能存放int值。

2.2不能使用instanceof运算符

1)不能使用instanceof运算符判断一个泛型类型是否与另一个有具体类型的泛型类型相同
(2)因为泛型擦除之后,ArrayList<String>只剩下原始类型,泛型信息String不存在了,所以没法使用instanceof。
(3)示例代码如下:
    public static void test2(){
    
    
        ArrayList<String> strings = new ArrayList<>();
        //s1.ArrayList<?> 可以使用instanceof,因为ArrayList<?>就是代表的是一种未知的类型,所以可以使用。
        if(strings instanceof ArrayList<?>){
    
    

        }

        //s2.因为ArrayList<String>泛型擦除之后,String类型为丢失,所以不能使用instanceof运行符
        if(strings instanceof ArrayList<String>){
    
    

        }
    }   

2.3泛型在静态方法和静态类中的问题

1)因为泛型类中的泛型参数的实例化是在定义泛型类型对象(比如ArrayList<Integer>)的时候指定的,而静态成员是不需要使用对象来调用的,所有对象都没创建,如何确定这个泛型参数是什么。所以静态方法与静态类中是不能够使用泛型的。
(2)示例代码如下:
public class Test2<T> {
    
    
    //s1.报错是因为泛型参数是要创建对象的时候才确定
    public static T one;

    public static T test(T t){
    
    }

    //s2.这里可以,是因为这是泛型方法,此T不是指的Test2<T>中的T
    public static <T> T test1(T t){
    
    
        return t;
    }
}3)为什么静态的泛型方法可以使用泛型呢?
是因为泛型方法是在调用的过程中来确定类型的,因此静态的泛型方法中是可以使用泛型的。

2.4泛型类型中的方法冲突

1)因为擦除后两个equals方法变成一样的了
(2)示例代码如下:
    //s1.因为泛型擦除之后,类型会变成Object,会和Object的equals()方法一样,相当于方法重复定义
    @Override
    public boolean equals(T t){
    
    

    }

    @Override
    public boolean equals(Object obj) {
    
    
        return super.equals(obj);
    }

2.5没法创建泛型实例

1)因为类型不确定,所以就无法创建泛型实例
(2)示例代码:
public class Test2 {
    
    
    //s1.无法创建一个类型参数的实例。例如:下面代码就会引起编译时错误:
    public static <E> void append(List<E> list){
    
    
        E elem = new E();
        list.add(elem);
    }

    //s2.通过反射创建一个参数化类型的实例
    public static <E> void append(List<E> list,Class<E> cls) throws Exception {
    
    
        E elem = cls.newInstance();
        list.add(elem);
    }
}

2.6 没有泛型数组的说法

2.6.1什么是Java数组的协变

(1)Apple extends Fruit
(2)可以认为Apple[] 的父类是 Fruit[],这种情况称为Java数组的协变。

2.6.2Java数组的协变引发的问题

1)为什么不能有泛型数组
(2)是因为当泛型信息被擦除之后,在运行期虚拟机就不知道它是什么类型了,就没办法满足Java数组的协变原则了,并且也不知道数组是什么类型的,所以就不允许有泛型数组。
(a)List<Apple>[]
(b)List<Fruit>[]

(2)示例代码1:

    public static <T> void test1(){
    
    
        Apple[] apples = new Apple[10];
        Fruit[] fruits = new Fruit[10];
        System.out.println(apples.getClass());
        System.out.println(fruits.getClass());
        fruits = apples;
        //s1.编译通过,运行时会报ArrayStoreException异常
        fruits[0] = new Banana();
        //s2.下列语句可以为什么?
        //(1)因为Plate<?>表示的是不知道类型的任意类型,所以是可以的,相当于Object
        Plate<?>[] plates = new Plate<?>[10];
    }

(3)示例代码2:

    public static <T> void test2(){
    
    
        //s1.Fruit是Apple的父类
        //s2.Fruit[]是Apple[]的父类,这就是Java数组的协变.
        //s3.如果加入泛型后,由于泛型的擦除机制,运行时将无法知道数组的类型。
        //s4.所以下列方式创建泛型数组是不允许的。
        Plate<Apple>[] applePlates = new Plate<Apple>[10];
    }
le[]的父类,这就是Java数组的协变.
        //s3.如果加入泛型后,由于泛型的擦除机制,运行时将无法知道数组的类型。
        //s4.所以下列方式创建泛型数组是不允许的。
        Plate<Apple>[] applePlates = new Plate<Apple>[10];
    }

猜你喜欢

转载自blog.csdn.net/xiogjie_67/article/details/108628411