在严格的泛型代码里,带泛型声明的类总应该带着泛型参数。但为了与老的Java
代码保持一致,也允许在使用带泛型声明的类时不指定实际的类型参数。如果没有为这个泛型类指定实际的类型参数,则该类型参数被称作raw type
(原始类型),默认是声明该参数时指定的第一个上限类型。
当把一个具有泛型信息的对象赋给另一个没有泛型信息的变量时,所有在尖括号之间的类型信息都将被扔掉。比如一个List<String>
类型被转换为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<Integer> a = new Apple<>(6); //①
// a的getSize方法返回Integer对象
Integer as = a.getSize();
// 把a对象赋给Apple变量,丢失尖括号里的类型信息
Apple b = a; //②
// b只知道size的类型是Number
Number size1 = b.getSize();
// 下面代码引起编译错误
Integer size2 = b.getSize(); //③
}
}
上面程序定义了一个带泛型声明的Apple
类,其类型形参的上限是Number
,这个类型形参用来定义Apple
类的size
变量。程序在①
处创建了一个Apple
对象,该Apple
对象传入了Integer
作为类型形参的值,所以调用a
的个体getSize()
方法时返回Integer
类型的值。当把a
赋值给一个不带泛型信息的b
变量时,编译器就会丢失a
对象的泛型信息,即所有尖括号里面的信息都会丢失,因为Apple
的类型形参的上限是Number
类,所以编译器依然知道b
的getSize()
方法返回Number
类型,但具体是Number
的哪个子类就不清楚了。
从逻辑上来看,List<String>
是List
的子类,如果直接把一个List
对象赋值给一个List<String>
对象应该引起编译器错误,但是实际上不会。对泛型而言,可以直接把一个List
对象赋给一个List<String>
对象,编译器仅仅提示”未经检查的转换”,看下面的程序:
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里的元素,如下面代码将引起运行时异常。
System.out.println(ls.get(0));
}
}
上面程序定义了一个List<Integer>
对象。这个List
对象保留了集合元素的类型信息,当把这个List
对象赋值给一个List
类型的list
后,编译器就会丢失前者的泛型信息,即丢失list
集合里元素的类型信息,这是典型的擦除。Java
又允许直接把List
对象赋值给一个List<Type>
(Type
可以是任何类型)类型的变量,所以程序在①
处可以编译通过,只是发出”未经检查的转换”警告。但对list
变量实际上引用的是List<Integer>
集合,所以当试图把该集合里的元素当成String
类型的对象取出时,将引发运行时异常。
下面的代码与上面的代码完全相似:
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
,将引发运行时异常。前面使用泛型代码时,系统与之存在完全相似的行为,所以引发相同的ClassCastException
异常。
附:源代码示例
公众号ID:longjiazuoA

未经允许不得转载:人生设计师 » 泛型系列(五):擦除和转换