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