1. 泛型擦除
泛型的擦除是是用一种称为类型消除( type erasure)的方法来实现的。
当泛型存在于编译时,一旦被确认安全使用时,
就会将其转换为原生类型也就是擦除成原生类型。
泛型擦除是指泛型代码在编译后,都会被擦除为原生类型。例如
Zoo<Fish>和Zoo<Bird>,实际上在运行时都是同一种类型,即
原生类型Zoo。这就意味着运行时,Java并不存在类型参数这一概念,
因此将无法任何相关的参数类型信息。
例如下面的代码证实了泛型擦除:
package Generic.wildcardsAndBoundaries;
public class Test {
public static void main(String[] args) {
Zoo<Fish> fishZoo = new Zoo<>(new Fish());
Zoo<Bird> birdZoo = new Zoo<>(new Bird());
System.out.println("两者的类型相同吗? " + fishZoo.getClass().equals(birdZoo.getClass()));
}
}
运行结果:
1.1 为什么要擦除泛型
擦除是java泛型方法实现的一种折中办法。
因为擦除的核心动机是使得泛化的代码可以使用非泛化的类库,
反之亦然,为了让非泛型的代码和泛型的代码共存,实现擦除非常可靠!
1.2 如何擦除
其实擦除的实质就是将原有的类型参数替换成即非泛化的上界。如:
public class Computer<E> {
private E e;
public Cmputer(E e){
this.e=e;
}
public E apply(){
return this.e;
}
}
上方代码经过编译后,将被编译成以下代码形式:
public class Computer {
private Object e;
public Computer(Object e) {
this.e = e;
}
public Object apply() {
return e;
}
}
通过比较你会发现原有类型参数消失了,取而代之为参数类型Object,
这是因为Computer<E>没有指明上界,编译器将其自动擦除成顶类Object类型
若指明了上界如<E extends electrical>,则会有如下翻译:
1.3 多边界擦除
2 泛型可以反射
3 泛型的限制和问题
因为擦除机制使得运行时丢失了泛型信息,
因此一些理所当然的功能在java泛型系统中得不到支持。
- 限制一:
为了保证类型安全,不能使用泛型类型参数创建实例
// 不合法 T object=new T() ; - 限制二:
不能声明泛型实例数组,这会导致运行错误
// 不合法 T[] numbers= new T[capcity];
但可以通过创建一个Object类型数组然后将它的类型转换E[]来规避这个限制。
T[] number= (E[])new Object[capcity]: - 限制三:
在静态的环境下不允许参数类型是泛型类型的。(由于泛型类的所有实例都有相同的运行时类,所以泛型类的静态变量和方法是被它的所有实例所共享的。既然是共享的你就没有必要再重新定义一样的泛型类型,那如果你不定义一样的泛型类型,又达不到共享(或者说是一致性),更没有必要让这种情况通过。所以,在静态环境了类的参数被设置成泛型是非法的。) - 限制四:
泛型类对象无法被抛出或捕获,因为泛型类不能继承或实现Throwable接口及其子类。