11

为什么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**
4

4 回答 4

3

泛型不是协变的。例如:

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。同样,l2is aList属于某种类型,即 is 或 extends Number。由于Integerextends Number,编译器知道分配l1l2必须是可以的。

这种情况不同:

<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;
于 2013-04-03T14:50:45.333 回答
1

顺便说一句:你不能扩展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;
于 2013-04-03T10:21:59.807 回答
-1

看看在 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;

会解决你的问题。。

于 2013-04-03T10:17:22.217 回答
-2

因为在 1 中,您分别说的是 Integer 和 Number 的任何子类。

但是在第二个中,您说的是 U 和 S 的泛型,并且像这样的泛型不支持 Super 可以参考 Java OOP 的子类对象概念。

于 2013-04-03T10:07:21.990 回答