Java Co-variant返回

时间:2016-03-08 17:01:43

标签: java return-type covariant

在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();
}
}

2 个答案:

答案 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将成为有效覆盖:

  1. Pb只有在Pa或父类(反式变体)时才有效;

    因为B.f必须至少能够获得Pa值。

  2. Rb可能仅在Ra或子类(共变体)时有效;

    因为B.f必须返回可分配给Ra的内容。

  3. 这使得子类更具限制性,具体。

    在手头的情况下,当DogFood是食物的孩子时,猫可能会返回DogFood。所以动物的食物确实是一种食物,即使动物实际上是猫。