为什么Java方法参数可以显式协变?
在Java中,可以使用为什么Java方法参数可以显式协变?,java,generics,covariance,Java,Generics,Covariance,在Java中,可以使用extends关键字声明给定类型参数是协变的。协方差和逆方差确实让我有点困惑,但我想我已经大致了解了它们。然而,在我的测试中,似乎Java类型参数本质上是协变的。那么,为什么我们可以明确地说明这一点呢 例如,我构建了一个如下所示的快速示例: public class Main<E> { protected E value; public Main(E value) { this.value = value; }
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());
}
}
公共类主{
保护E值;
公用干管(E值){
这个值=值;
}
公共无效设置值(T值){
这个值=值;
}
公共E getValue(){
返回值;
}
公共静态void main(字符串[]args){
主示例=新主(0升);
System.out.println(例如.getValue().getClass().getCanonicalName());
例如,设置值(32.0);
System.out.println(例如.getValue().getClass().getCanonicalName());
}
}
使用的类型是Number,它是所有装箱类型的超类。在构造函数中,它接受一个声明为E类型的参数(在本例中为数字)。另一方面,在setValue
方法中,它接受一个声明为扩展类型E的任何参数。两个println调用都返回正确的值(首先java.lang.Long
,然后java.lang.Double
)
在我看来,除去泛型,仍然可以传递子类。如果该类是在没有类型参数的情况下声明的,并且方法/构造函数接受/返回了数字,那么它仍然可以正常工作
那么在这种情况下,
extends
关键字的用途是什么呢?在这种情况下,在setValue
中使用extends
没有任何好处。您是对的,由setValue
声明的T
可以替换为其上限E
:
public void setValue(E value) {
this.value = value;
}
但请考虑这一点:
public <T extends E> T setValueAndGiveItBack(T value) {
this.value = value;
return value;
}
如果没有T
,最具体的类型示例.setValueAndGiveItBack
可以返回Number
只是澄清一下,类型参数本质上是协变的,这一点也是正确的。使用
extends
的原因是限制类型参数的上限。例如,
是隐式的
。在上面的示例中,如果不将E
声明为T
的上限,我们将无法将值
分配给此.value
,因为它可以是任何有意义的对象,谢谢!我试图编写一个系统,它实际使用的值与此类似,基类是泛型的,并持有一个类型为“E”的值,然后子类在此基础上展开。我并没有真正理解这一点,我继续使用了基本上所有的方法,认为我需要使用一些类似于setValue()
的方法。现在我明白了,我真的不知道。这应该有助于清理我的代码很多,谢谢!
Double d = example.setValueAndGiveItBack(32.0);