为什么1有效而2无效?
1:
public List<? extends Integer> l1;
public List<? extends Number> l2 = l1;
2:
public List<U> l1;
public List<S> l2 = l1;
//where U and S have been previously defined as: **S extends Number,U extends Integer**
泛型不是协变的。例如:
List<Integer> l1;
List<Number> l2;
l1 = l2; // incompatible types
l2 = l1; // also incompatible
但是,通配符类型提供了一种表达协方差的方法:
List<? extends Integer> l1;
List<? extends Number> l2 = l1; //legal
l1
被表示为List
某种未知类型的 a 或 extends Integer
。同样,l2
is aList
属于某种类型,即 is 或 extends Number
。由于Integer
extends Number
,编译器知道分配l1
给l2
必须是可以的。
这种情况不同:
<S extends Number, U extends Integer> void someMethod() {
List<U> l1;
List<S> l2 = l1; //incompatible types
}
S
并且U
是类型参数,这意味着它们由调用者someMethod
(或类型推断)提供一些特定的类型参数。这些类型参数可以是具体类型Integer
或通配符捕获。
虽然它们也是有界的,但这与使用上面的有界通配符不同。类型参数在声明时是有界的——在方法体中它们被理解为不会改变。例如,让我们说两者S
,并通过调用U
解决:Integer
this.<Integer, Integer>someMethod();
在这种情况下,我们可以想象方法体如下所示:
List<Integer> l1;
List<Integer> l2 = l1; // okay why not?
这将是合法的,但我们只是碰巧走运了。有很多情况是不会的。例如:
this.<Double, Integer>someMethod();
现在我们重新构想方法体:
List<Integer> l1;
List<Double> l2 = l1; // danger!
所以你可以看到有界类型参数与有界通配符有很大不同,它允许不同的泛型类型协变地“交换”:
List<Integer> l1;
List<Double> l2;
List<? extends Number> l3;
l3 = l1;
l3 = l2;
顺便说一句:你不能扩展Integer
,Integer
是一个final
类。
// l1 holds any subclass of Integer and, because Integer implements Number it is also a subclass of Number
public List<? extends Integer> l1;
// l1 (see above) implements Number so this is fine.
public List<? extends Number> l2 = l1;
// Using Integer here instead of your U because you cannot extend Integer - it is final.
public List<Integer> l3;
// Make S extend Number
static class S extends Number {
// Implementing the abstract methods of Number
}
// NOT valid because l4 must be a List of S not a list of ANY Number and l3 is a List<Integer> - no connection other than a commmon interface.
public List<S> l4 = l3;
看看在 1.1 中,您说的是任何扩展 Integer 的类,而在 1.2 中是任何扩展 Number 的类。现在是这样的 Integer 是 Number 的子类,这就是为什么它在第一种情况下没有给出任何错误的原因。但是在 2.1 中你只说 U 而在 2.2 中只说 S 而你正在做
public List<S> l2 = l1
并且 l1 的类型是 U 而不是 S 并且泛型不支持它自己的此类对象引用。您将不得不使用第一种情况中使用的通配符。
public List<? extends Number> l2 = l1;
会解决你的问题。。
因为在 1 中,您分别说的是 Integer 和 Number 的任何子类。
但是在第二个中,您说的是 U 和 S 的泛型,并且像这样的泛型不支持 Super 可以参考 Java OOP 的子类对象概念。