然后下一个代码是编译:
List<Number> list1 = null;
List<? super Integer> list2 = null;
list2 = list1;
虽然此代码未编译:
List<? super Number> list1 = null;
List<? extends Integer> list2= null;
list1 = list2;
问题是为什么?
答案 0 :(得分:5)
让我们看看如果编译它会出错:
// Suppose list1, and list2 are initialized like this
List<? super Number> list1 = new ArrayList<Object>(); // valid assignment
List<? extends Integer> list2 = new ArrayList<Integer>(); // valid
// had this been valid, list1 and list2 both point to ArrayList<Integer>
list1 = list2;
// This is fine, as list1 declared type is `List<? super Number>`
list1.add(new Float(2.4f));
// The below code will compile fine, as list2.get(0) type is Integer.
// But it would throw ClassCastException at runtime.
Integer in = list2.get(0);
因此,为避免运行时,编译器会给出编译时错误。
然而,对于第一种情况,您以某种方式颠倒了分配,因此2代码之间的比较没有意义。将第一个代码更改为:
List<Number> list1 = null;
List<? super Integer> list2 = null;
list1 = list2;
它也会失败。
此外,在第二个代码中反转赋值也会使代码无法编译。
一些解释:
你必须记住的是,超类引用可以指向子类对象,但不能反过来。如果可以从list1
捕获转换的所有列表也可以从声明的list2
类型中捕获转换,则赋值list2 = list1
将是有效的,否则将无法编译。
第一个代码:
List<? super Integer>
可以被捕获转换为以下列表:
List<Integer>
List<Number>
List<Object>
List<Serializable>
由于列表中有List<Number>
,因此作业list2 = list1
有效,因为list1
只能指向List<Number>
。但是,反向分配list1 = list2
无效,因为List<Integer>
不是List<Number>
的子类型。
同样,对于第二个代码:
List<? super Number>
可以被捕获转换为:
List<Object>
List<Serializable>
List<Number>
List<? extends Integer>
可以被捕获转换为:
List<Integer>
由于List<Integer>
无法从List<? super Number>
进行捕获转换,因此list1 = list2
无效。
此外,由于List<Object>
和所有其他列表无法从List<? extends Integer>
进行捕获转换,因此list2 = list1
也无效。
答案 1 :(得分:0)
(1)在第一个示例中,List<Number>
由List<? super Integer>
“捕获”。 List<Number>
是List<? super Integer>
。
(2)但在第二个示例中,List<? extends Integer>
例如,您可以将List<? super Number>
添加到Number
,但不能将非List<? super Number>
Integer
添加到Number
。
List<? extends Integer>
因此,您无法将List<? super Number> list1 = new ArrayList<Number>();
list1.add(0.5); //okay
List<? extends Integer> list2 = new ArrayList<Integer>();
list2.add(0.5); //not okay
指定为list1
,因为list2
不支持list2
类型的所有内容。