相信大家对于泛型都有或多或少的理解,但是泛型擦除这个词可能很少听说过也很少能够用的到。
一、泛型擦除:在java编程思想(第四版)中提到它是解决 java泛型支持向后兼容性和迁移兼容性的唯一可行方案。
简单解释一下这两个特性:
在我们编写集合时,普遍会用到泛型,例如:
List<String> list = new ArrayList<String>();
但是我们也可能这样声明:
List list = new ArrayList();(下接三)
二、在泛型代码内部,将有关泛型参数的类型信息擦除到第一个边界。如果该参数没有指定边界,那么直接擦除到Object,也就是说,在泛型代码内部,无法获得任何有关泛型参数类型的信息。例如:
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1==c2);
在编译时编译器会将new ArrayList中的泛型参数全部擦除掉。也就是说编译器是先将
new ArrayList<String>、new ArrayList<Integer>中的类型参数擦除掉,使其全部变成ArrayList类型,然后才将此类型赋值给c1,c2.所以在下边的比较中,c1和c2的类型是相同的。
三、这时候问题就出现了,拿jdk1.4到jdk1.5这个重大的变更来说(jdk支持了泛型),jdk1.4的类库中是不支持泛型的,但是到了jdk1.5以后,集合类普遍已经支持了使用泛型。那么问题来了,这么巨大的变更,(1).如何保证jdk1.5能够正确的支持jdk1.4时代或者更早的时候出现的代码;(2).又如何能保证在jdk1.5之后开发的代码使用了泛型,但是所用到的类库并没有使用泛型,这个时候在开发时编译器不会报错,并且代码能够正确无误的执行。(3)保证泛型这个概念在jdk1.5以后可以像他们想象的那样能够使用,并且不影响以前的代码。
如下:
/**
* 研究泛型擦除的内部逻辑
* @author YR123
*
*/
public interface Cachu{
public void get();
public void set();
}
class CachuClass1 implements Cachu{
@Override
public void get() {
System.out.println("get");
}
@Override
public void set() {
System.out.println("set");
}
public void run(){
System.out.println("run");
}
}
/**
* 测试类见Test01
* @author YR123
*
*/
class CachuClass2 implements Cachu{
@Override
public void get() {
System.out.println("get");
}
@Override
public void set() {
System.out.println("set");
}
/**
* 泛型方法,因为设置了边界,所以在泛型方法中可以使用Cachu接口中的方法,
* 如果没有设置边界,则在CachuClass2类中会将a的信息擦除成Object,此时肯定无法调用泛型方法
* @param a
*/
public <A extends Cachu>void post(A a){
a.get();
a.set();
//会报错,让转换成CachuClass1类型
//a.run();
}
/**
* boundary 边界
* @param a
*/
public <A> void noBoundary(A a){
//会报错,因为此刻A已经被擦除成Object,编译器在A中找不到get、set方法
/*a.get();
a.set();*/
//此时只有Object类中独有的方法可以正常编译
a.equals(new Object());
}
}
只是自己的理解,欢迎大家批评指正。