在java中,当非协变返回类型产生编译时错误时,为什么协变返回类型是可接受的。当然,如果JVM可以处理协变返回类型,那么它可以处理非变量返回类型。我假设当java看到带有协变返回的重写方法时,它只应用与调用对象关联的方法。为什么不协变返回类型会发生同样的情况。 我的猜测是违反了超类的条款。方法契约,当然如果允许,那么子类(被覆盖的)方法的行为是不可预测的(因为返回类型没有一致性)?
以下是一个例子(假设DogFood是Food的子类,但CatFood不是Food的子类):
动物类
public class Animal {
public Food seekFood() {
return new Food();
}
}
狗班
public class Dog extends Animal {
public DogFood seekFood() { //This is OK since its a covariant
return new DogFood();
}
}
猫类
public class Cat extends Animal {
public CatFood seekFood() { // This won't compile. Catfood is not covariant
return new CatFood();
}
}
答案 0 :(得分:0)
如果两个方法具有相同的签名(方法名称和参数类型),编译器将无法决定选择调用哪个方法。如果两个方法具有相同的名称,但不同的参数类型和不同的返回类型 - 它们具有不同的签名,然后编译器可以选择调用哪个。
<强>更新强> javac将共同变量方法编译到它的基类方法当你调用它时,基类方法委托调用子类方法。由于它们返回不同类型,因此无法进行类型转换。感谢A. Sundararajan's Weblog,可以使用一个代码段非常清楚地解释该过程:
class CircleFactory extends ShapeFactory {
public Circle newShape() {
// your code from the source file
return new Circle();
}
// javac generated method in the .class file
public Shape newShape() {
// call the other newShape method here -- invokevirtual newShape:()LCircle;
}
}
答案 1 :(得分:0)
class A {
Ra f(Pa x) { ... }
}
class B extends A {
@Override
Rb f(Pb x) { ... }
}
继承规则确定共变体/反变体行为:
类型T的值只能分配给T类型或父类型的变量。
方法调用意味着将其实际方法参数(1)分配给本地参数(2),并将结果值(1)分配给要使用的某个位置(2)。
现在,如果编译器遇到一个实际上可以是B的A对象,那么B.f
将成为有效覆盖:
Pb只有在Pa或父类(反式变体)时才有效;
因为B.f
必须至少能够获得Pa值。
Rb可能仅在Ra或子类(共变体)时有效;
因为B.f
必须返回可分配给Ra的内容。
这使得子类更具限制性,具体。
在手头的情况下,当DogFood是食物的孩子时,猫可能会返回DogFood。所以动物的食物确实是一种食物,即使动物实际上是猫。