在Java中,您可以使用extends
关键字来声明给定的类型参数是协变的。协方差和逆变确实让我感到困惑,但我想我已经对它们有了一般的认识。但是,在我的测试中,似乎Java类型参数本身协变。那么我们为什么要明确说明呢?
例如,我构建了一个如下所示的快速示例:
public class Main<E> {
protected E value;
public Main(E value) {
this.value = value;
}
public <T extends E> void setValue(T value) {
this.value = value;
}
public E getValue() {
return value;
}
public static void main(String[] args) {
Main<Number> example = new Main<Number>(0L);
System.out.println(example.getValue().getClass().getCanonicalName());
example.setValue(32.0);
System.out.println(example.getValue().getClass().getCanonicalName());
}
}
使用的类型是Number,所有盒装类型的超类。在构造函数中,它接受一个声明为E类型的参数(在本例中为Number)。另一方面,在setValue
方法中,它需要一个声明为扩展类型E的参数。两个println调用都返回正确的值(第一个java.lang.Long
,然后java.lang.Double
)。
我看到它的方式,删除泛型,你仍然可以传递子类。如果声明的类没有类型参数,并且方法/构造函数接受/返回Numbers,那么它仍然可以正常工作。
那么在这种情况下extends
关键字的目的是什么?
答案 0 :(得分:5)
在这种情况下,在extends
中使用setValue
没有任何好处。您T
声明的setValue
可以替换为其上限E
,这是对的:
public void setValue(E value) {
this.value = value;
}
但请考虑一下:
public <T extends E> T setValueAndGiveItBack(T value) {
this.value = value;
return value;
}
这意味着我们可以这样做:
Double d = example.setValueAndGiveItBack(32.0);
如果没有T
,则最具体的example.setValueAndGiveItBack
类型可能会返回Number
。
只是为了澄清,你也是对的,类型参数本质上是协变的。使用extends
的原因是限制类型参数的上限。例如,<T>
隐含<T extends Object>
。在上面的示例中,未将E
声明为T
的上限,我们无法将value
分配给this.value
,因为它可能是Object
{{1}} }}