然后下一个代码正在编译:
List<Number> list1 = null;
List<? super Integer> list2 = null;
list2 = list1;
Run Code Online (Sandbox Code Playgroud)
虽然此代码未编译:
List<? super Number> list1 = null;
List<? extends Integer> list2= null;
list1 = list2;
Run Code Online (Sandbox Code Playgroud)
问题是为什么?
让我们看看如果它编译会出现什么问题:
// 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);
Run Code Online (Sandbox Code Playgroud)
因此,为避免运行时,编译器会给出编译时错误.
然而,对于第一种情况,你以某种方式颠倒了赋值,因此2代码之间的比较没有意义.将第一个代码更改为:
List<Number> list1 = null;
List<? super Integer> list2 = null;
list1 = list2;
Run Code Online (Sandbox Code Playgroud)
它也会失败.
另外,在第二个代码中反转赋值也会使代码无法编译.
一些解释:
你必须记住的是,超类引用可以指向子类对象,但不能反过来.如果所有可以捕获转换的列表list1也是从声明的类型中捕获可转换的list2,那么赋值list2 = list1将是有效的,否则它将无法编译.
对于第一个代码:
List<? super Integer> 可以捕获转换为以下列表:
List<Integer>List<Number>List<Object>List<Serializable>由于List<Number>列表中存在,因此赋值list2 = list1是有效的,因为list1只能指向a 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也是无效的.