目录
1. 类型擦除
对于泛型,代码编译完成后,编译器会丢弃类型参数的类型信息,此类型信息在运行时不可用。
现在有People类:
public class People
{
String name;
public People(String name)
{
this.name=name;
}
}
基于People的GoodPeople类:
public class GoodPeople extends People
{
int grade;
public GoodPeople(String name, int grade)
{
super(name);
this.grade=grade;
}
}
如果我们在User类中,进行如下操作:
ArrayList<People> list=new ArrayList<GoodPeople>();
会产生错误提醒:“类型不匹配:不能从 ArrayList<GoodPeople> 转换为 ArrayList<People>”。原因就是类型擦除:编译器编译时会将泛型类中的所有类型参数替换为边界。
2. 解决方案:通配符<?>
<? extends >来实现泛型类的类型参数替换为子类的操作;
ArrayList<? extends People> tp=new ArrayList<GoodPeople>();
<? super >来实现泛型类的类型参数替换为父类的操作。
ArrayList<? super GoodPeople> tp1=new ArrayList<People>();
基于<? extends >,进行下列操作:
public class User
{
public static void main(String[] args)
{
People peo=new People("Bob");
System.out.println(peo1);
GoodPeople gpeo=new GoodPeople("Bob", 1);
System.out.println(gpeo);
ArrayList<? extends People> tp=new ArrayList<GoodPeople>();
tp.add(peo);
}
}
将产生错误:“类型 ArrayList<capture#1-of ? extends People> 中的方法 add(capture#1-of ? extends People)对于参数(People)不适用”。
同样的,进行操作
tp.add(gpeo);
将产生错误:“类型 ArrayList<capture#1-of ? extends People> 中的方法 add(capture#1-of ? extends People)对于参数(GoodPeople)不适用”。
因此对于通配符实现的泛型,调用正常类型的方法,依然会出现错误。(这里笔者没有找到使用通配符?之后依然可以正确调用类似add等方法的正确形式)
考虑接下来的代码:
public class User
{
public static void main(String[] args)
{
People peo1=new People("Bob");
System.out.println(peo1);
People peo2=new People("Ben");
System.out.println(peo2);
GoodPeople gpeo1=new GoodPeople("Bob", 1);
System.out.println(gpeo1);
GoodPeople gpeo2=new GoodPeople("Ben", 2);
System.out.println(gpeo2);
ArrayList<GoodPeople> tg=new ArrayList<>();
tg.add(gpeo1);
tg.add(gpeo2);
ArrayList<? extends People> tp=tg;
for(People ti : tp)
{
System.out.println(ti);
}
}
}
编译通过,且运行结果:
.People@68d4972d
.People@712c766
.GoodPeople@51683ae3
.GoodPeople@5ff33cde
.GoodPeople@51683ae3
.GoodPeople@5ff33cde
可以看出,初始声明时变量存储的地址,在使用通配符之后,地址依然不变。