要记住,泛型是为容器设计的,虽然泛型不仅仅只能用在容器设计上。在脑海中具象化的时候一定要有这个概念。
泛型,意思是类型参数化,类型是可变的。
泛型能够做的什么?
1. 参数的类型检查
编译器会检查参数的类型是否符合泛型。
2. 覆盖时自动创建桥方法适配
底层是Object或者限定边界,在重写的时候使用的具体类型,所以自动生成一个桥方法,使用底层参数类型,内部调用具体实现的具体参数类型的方法,来实现覆盖保证多态。
3. 调用后类型强制转换
可以利用泛型语法,让编译器在调用泛型方法或者属性的语句加上类型强制转换。
4. 实现多参数之间的类型关系
让多个参数只要是同一类型,
泛型语法
类与方法的类型参数定义
泛型有两种,类的泛型,和方法的泛型。
类泛型通过 class ClassName<T>来定义,泛型参数在类作用域中都可以使用
方法泛型就像这样 public static final <T> void methodName(T t)定义,在方法的参数上
传递类型
传递给类,传递给方法
传递给类只能显式传递,通过实例化时的<>,来传递具体的类型名
传递给方法只能隐式传递,通过具体参数,传递参数所属类型
通配表达
三个符号:?extends super
使用?只是为了不将具体类型传递给类型参数,也就是不需要的情况。所以类型变量完全可替代通配符?。
只有具体类型可以实例化泛型类。
可以创建通配泛型变量,来引用其可包含的具体泛型类实例。
extends和无限制通配泛型变量无法执行修改(写)操作,原因是同一个父类的子类,相互不兼容,在不知道内部具体的泛型之前,很可能导致修改类型和内部泛型不一致,所以这种操作直接禁止。
而super通配泛型变量可以执行写操作,因为super所代表的内部具体类型的泛型类,一定是父类,所以修改的类型一定属于内部泛型的子类,那么子类可以上转型到父类,就允许操作。
传递泛型的语法,可以让具体类型从通配泛型变量中传递给方法的泛型参数,从而通过方法的具体类型泛型变量来执行修改。
private static <T> void swapInternal(DynamicArray<T> arr, int i, int j){
T tmp = arr.get(i);
arr.set(i, arr.get(j));
arr.set(j, tmp);
}
public static void swap(DynamicArray<? > arr, int i, int j){
swapInternal(arr, i, j);
}
通配表达可以用在泛型类的定义上,也可以用在创建一个泛型变量上(而不是实例化)。
例如定义:
class MyClass< T extends Number>{
...
}
例如实例化:
MyClass<? extends Number> myClass = new MyClass<Integer>();
局限性
基本数据类型不能作为实例化类型参数(但在自动装箱机制下解决,只在<>中无法使用基本数据类型的类型名)。
运行时类型信息不适用于泛型(因为类型擦除,被Object或者它们的限定边界来替换)
关于类型判断
因为类型擦除,对泛型对象的类型,和原始类型相同。
如果A<T extends Comparable>,那么编译后就会用Comparable代替。
所以不会因为不同的类型参数,导致对象的类型不同。但是instanceof语法有变,仅支持无限定通配符版的类型作为instanceof的判断类型。
支持if(p1 instanceof Pair<? >) 而不支持 instanceof Pair<Interger>等具体的类型参数。
重载的反常识
因为类型擦除的关系,只要泛型类的原型是同一个,那么就是同一类型,无法构成重载。
多态问题
我们知道,为了实现多态,编译器会生成桥方法。
但是对于无参数类型的方法,会导致
如果想重写父类实现的泛型接口,在编译器和底层实现上会出现冲突。
实际上重写的方法都是Object底层参数,而想要不同的类型参数,也就是不同的类型检查。这样会导致
1677

被折叠的 条评论
为什么被折叠?



