为什么 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**
最佳答案
Generics are not covariant .例如:
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
,它是或扩展 Integer
。类似地,l2
是某种类型的 List
,它是或扩展了 Number
。由于 Integer
扩展了 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;
关于Java 通配符与类型参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15784344/