Java泛型奇怪的行为

Ily*_*man 0 java generics

在Java中,Integer扩展了Number

然后下一个代码正在编译:

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)

问题是为什么?

Roh*_*ain 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);  
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也是无效的.