版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/xiao_dondon/article/details/77944038
看一段简单的代码:
public class Main {
public static void main(String[] args) {
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
//list1 = list2; compile error
Object obj = list2;
}
我们可以看到,虽然String是Object的祖先类,但是list2却不能赋值给list1(编译出错).
原因是,假如可以赋值的话,我们往list2中添加Object对象会破坏list1的类型安全;另外,当从list2中取出元素时无法判断元素类型。
当然,Object是所有类的祖先类,所有list2可以赋给obj。
为了解决上面的问题,Java中提供了通配符(?)
我们再看一段代码:
List<? extends String> list3 = new ArrayList<>();
List<? extends Object> list4 = new ArrayList<>();
//list3 = list4;compile error
list4 = list3;
obj = list3;
obj = list4;
使用通配符之后,list3就可以赋给list4了。
继续看代码:
String s = list3.get(0);
String ss = list4.get(0);// 1 compile error
obj = list4.get(0);
使用通配符之后,集合中的元素都会以通配的类型存储,取出来的元素也将是通配的类型,所以代码1出编译出错
通配符的好处:
fon(list1);
fon(list2);
fon(list3);
fon(list4);
public static void fon(List<?> list){
}
public static void fon(List<? extends String> list){
}
public static void fon(List<? extends Object> list){
}
当一个类中出现上述2个方法时,编译出错。
我们接下来看一个类似的结构:数组
Object[] o = new Object[10];
String[] str = new String[10];
o = str;
o[0] = new Object();
上述代码在编译期间是不报任何错误的。这是数组与集合泛型的区别,我们可以将子类数组对象赋给父类。
但是在运行时时会报错的: java.lang.ArrayStoreException;
虽然我们把str数组付给了o数组,但是当我们往数组中插入非String类型的元素时,会报上述异常。
继续:
o[0] = new String("123");
Object s1 = o[0];
System.out.println(s1);
上述代码编译运行都是正常的。也就是说,尽管我们把str数组赋给了o数组,但是我们只能插入String元素,而取出来的元素默认却是Object类型的。
原因:
Java中集合的泛型是伪泛型,就是说,泛型只作用于编译阶段,一旦编译成.class文件之后,泛型信息就会被擦除,这时候,无论往集合中插入什么类型的元素都是没有问题的;
而数组不同,即使编译过后,在运行阶段仍然能够判断数组类型,不允许非数组类型元素的插入。