泛型
- 泛型可以是有泛型类和泛型方法。
泛型的优点:1.避免了方法的重载,一种泛型方法可以作用于多种类型,2.避免了用Object类编写多种类型的代码,多次使用向下转型的复杂情况。3.使代码更简单易读,也更安全。
常用类型变量:K、T、V、U。其中,习惯上用E表示集合类型,用K、V表示键和值的类型。U、S表示“任意类型”。
限定类型
在泛型中接上extends
,如<T extends Person>
,Person即是限定类型。extends可以接多个接口用&隔开,也可以接类,但是类必须放在第一个。
为什么是extends,众所周知,extends后面接的应该是类,但这里接了接口。选择extends的原因是它更接近子类型的概念(书中原话)。即类型转换的时候可以使用该类型及其子类型。
泛型的类型擦除
在编译期间,所有的泛型信息都会被擦除,替换为原生类型和限定类型。
生成的字节码不包含泛型中的类型信息,使用泛型的时候加上类型参数,而在编译期编译的时候去掉,这个过程称为类型擦除。
有限定类型使用限定类型进行类型转换,无限定类型的时候转换为Object类型。
泛型的问题
会出现运行时刻出现类型转换异常的情况
编译时类型&运行时类型
左侧的引用变量在编译时只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。
泛型问题的解决方法
先检查、再编译,以及检查编译对象和引用传递的问题。
泛型会在编译成字节码阶段进行类型的擦除,为了防止错误的发生,编译器会在编译之前进行代码泛型类型匹配的检查。
ArrayList<String> arr1 = new ArrayList(); //第一种方式可以实现泛型
ArrayList arr2 = new ArrayList<String>(); //第二种方式不可以实现泛型
在创建对象时,对象的左边是编译时类型,会在编译前检查,右侧是运行时类型,在运行时进行检查。
所以左侧在编译前编译前时去检查匹配类型类型不符合则编译不通过,可以实现泛型;右侧的在编译时类型被擦除了,运行时的类型就为Object类型
- 若父类有方法是泛型方法,子类继承父类时,要“重写”父类的方法。但这个“重写”的方法和父类的方法并不是重写关系,而是“重载”的关系。这就会造成问题。所以JVM虚拟机会自动生成一个桥方法,这个方法才是真正的父类的重写方法。这个重写方法内会调用自己“重写”的那个方法,实现连接
为什么泛型内用的是包装类而不能是基本类型
因为泛型在编译后会被类型擦除,替换为Object类型,Object类型是一个对象类型,而基本类型不是对象。
参考:https://developer.aliyun.com/article/313278