擦除和转换
在严格的泛型代码里,带泛型声明的类总应该带着类型参数,但是也允许使用带泛型声明的类时不指定实际的类型,如果没有为这个泛型类指定实际的类型,则称作原始类型,默认是声明该泛型形参时指定的第一个上限类型
当把一个具有泛型信息的对象赋给另一个没有泛型信息的变量时,所有在尖括号之间的类型信息都将被丢掉,例如List类型被转换为List,则该List对集合元素的类型检查变成了泛型参数的上限即Object
class Apple<T extends Number>
{
T size;
public Apple()
{
}
public Apple(T size)
{
this.size = size;
}
public void setSize(T size)
{
this.size = size;
}
public T getSize()
{
return this.size;
}
}
public class ErasureTest
{
public static void main(String[] args)
{
// 创建Apple对象,该Apple对象a的泛型代表了Integer类型
Apple<Integer> a = new Apple<>(6);
// a的getSize方法返回Integer对象
Integer as = a.getSize();
// 把a对象赋给Apple变量,丢失尖括号里的类型信息
Apple b = a;
// 因为Apple类的泛型形参的上限是Number类,所以size1是Number类型,但具体是Number的哪个子类就不知道了
Number size1 = b.getSize();
// 下面代码引起编译错误
// Integer size2 = b.getSize();
}
}
如代码所示声明了一个带泛型声明的Apple类,其泛型形参的上限是Number,这个泛型形参用来定义Apple类的size变量
理论上说List是List的子类,如果直接把一个List对象赋值给一个List对象应该是会引起编译错误的,但实际是不会的,对于泛型而言,只会提示“未经检查的转换”
import java.util.*;
import static java.lang.System.*;
public class ErasureTest2
{
public static void main(String[] args)
{
List<Integer> li = new ArrayList<>();
li.add(6);
li.add(9);
List list = li;
// 下面代码引起“未经检查的转换”的警告,编译、运行时完全正常
List<String> ls = list;
// 但只要访问ls里的元素,如下面代码将引起运行时异常。
out.println(ls.get(0));
}
}
类似的是:
public class ErasureTest2
{
public static void main(String[] args)
{
List li = new ArrayList();
li.add(6);
li.add(9);
System.out.println((String)li.get(0));
}
}
程序试图从li中获取一个元素,并且试图通过强制类型转换把它转换成一个String,将引发运行时异常