前面提到过,Java泛型是1.5才引进来的,不像其他语言天生就支持泛型。为了兼容1.5之前的代码,Java从编译器动手,使用擦除的手段支持泛型,这也使得Java的泛型有局限性。下面讲解擦除的原理及其局限性,对Java泛型有个全面的了解,在使用泛型的时候不再疑惑。
擦除
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
System.out.println(strList.getClass().getName()); //java.util.ArrayList
System.out.println(intList.getClass().getName()); //java.util.ArrayList
System.out.println(strList.getClass() == intList.getClass()); //true
可见,在运行时List<String>与List<Integer>的类型信息是一样的
class Holder<T>{
private T t;
public Holder(T t){
this.t = t;
}
}
Holder<String> stringHolder = new Holder<>("str");
Holder<Integer> intHolder = new Holder<>(123);
System.out.println(Arrays.toString(stringHolder.getClass().getTypeParameters())); //[T]
System.out.println(Arrays.toString(intHolder.getClass().getTypeParameters())); //[T]
getTypeParameters返回泛型声明对应的类型参数,从打印上看到并不是返回具体的类型,二是返回[T],是一个占位标识符。
泛型会擦除掉类型参数,类里面的声明会变成类型边界(类型边界后面会讲到),如果没有声明类型边界就是Object。当你想使用T的时候,不知道它具体的类型,只能当做类型边界的类,调用它的方法。
擦除只是在使用T的时候,上面看到stringHolder.get()的时候编译器会自动帮我们把返回的参数转换为String类型
边界
class Animal{
private String name;
public Animal(String name){
this.name = name;
}
public String getAnimalName() {
return name;
}
}
class Holder<T>{
private T pet;
public Holder(T t){
pet = t;
}
}
class Holder2<T extends Animal>{ //声明Animal为类型参数的边界
private T pet;
public Holder2(T t){
pet = t;
pet.getAnimalName(); //类型擦除到第一边界,可以有多个边界
}
}
Holder2声明了类型参数的边界,编译器实际上会把类型参数替换为它的擦除,T就相当于Animal,pet就行可以使用Animal的方法,相应地pet也只能接收Animal或者Animal的子类
Holder2 holder2 = new Holder2<>(new Animal("aaa"));
Holder2 holder3 = new Holder2<>(new Dog("bbb"));
Holder2 holder4 = new Holder2<>(new Object()); //编译不通过
多边界
边界可以定义多个,与集成一样,只能定义一个class的边界+多个接口的边界,并且class必须放在开始
class Animal{
private String name;
public Animal(String name){
this.name = name;
}
public String getAnimalName() {
return name;
}
}
interface Fly{
void fly();
}
interface Run{
void run();
}
class Holder<T extends Animal & Fly & Run>{
}
目录
学会Java泛型系列(零):简介及目录
学会Java泛型系列(一):Java泛型
学会Java泛型系列(二):泛型定义与使用
学会Java泛型系列(三):泛型原理-擦除
学会Java泛型系列(四):擦除带来的问题以及解决办法
学会Java泛型系列(五):限定符
学会Java泛型系列(六):常用案例
网友评论