Java联合变量返回

Java联合变量返回,java,return-type,covariant,Java,Return Type,Covariant,在java中,当非协变返回类型产生编译时错误时,为什么协变返回类型可以接受。当然,如果JVM可以处理协变返回类型,那么它就可以处理非协变返回类型。我假定,当java看到一个具有协变返回的重写方法时,它只应用与调用对象关联的方法。为什么非协变回报类型不能发生同样的情况。 我的猜测是,这与打破超类方法契约的条款有关,当然,如果允许这样做,那么子类(重写)方法的行为就不是很可预测的(因为返回类型没有一致性) 这里有一个例子(假设狗粮是食物的一个子类,但猫粮不是食物的一个子类): 动物类 public

在java中,当非协变返回类型产生编译时错误时,为什么协变返回类型可以接受。当然,如果JVM可以处理协变返回类型,那么它就可以处理非协变返回类型。我假定,当java看到一个具有协变返回的重写方法时,它只应用与调用对象关联的方法。为什么非协变回报类型不能发生同样的情况。 我的猜测是,这与打破超类方法契约的条款有关,当然,如果允许这样做,那么子类(重写)方法的行为就不是很可预测的(因为返回类型没有一致性)

这里有一个例子(假设狗粮是食物的一个子类,但猫粮不是食物的一个子类):

动物类

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

如果两个方法具有相同的签名(方法名和参数类型),编译器将无法决定选择调用哪个方法。如果两个方法具有相同的名称,但参数类型和返回类型不同-它们具有不同的签名,那么编译器可以选择调用哪一个

更新: javac将协变量方法编译成它的基类方法,当您调用它时,基类方法将调用委托给子类方法。因为它们返回不同的类型,所以不能进行类型转换。多亏了,这个过程可以用一个代码片段解释得非常清楚:

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;
    } 
}
继承规则决定共变/反变行为:

类型T的值只能分配给类型T或父类型的变量。

方法调用意味着将其实际方法参数(1)分配给局部参数(2),并将结果值(1)分配给要使用的某些位置(2)

现在,如果编译器遇到了一个实际上可以是A B的A对象,那么
B.f
就是一个有效的覆盖:

  • Pb仅在其为Pa或父类(反向变量)时有效

    因为您必须能够接收至少一个Pa值

  • Rb仅在其为Ra或子类(共变体)时有效

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

  • 这使得子类更加严格、具体


    在本案中,当狗粮是食物的孩子时,猫可能会退回狗粮。因此,任何动物的食物实际上都是食物,即使动物实际上是一只猫。

    我实际上没有理解你的意思。。这可能是个好问题,但请举例说明。。在我的例子中,这三种方法都有相同的签名。但是,它们都有不同的返回类型。对于协变函数,编译器不会抱怨,并且可以选择调用哪个方法;它根据对象类型确定要调用的方法。在Cat示例中,Catfood不是食物的协变变量,因此Cat的seekFood方法不会编译。为什么呢?我怀疑JVM可以将其视为协变变量,但如果它这样做,那么我猜您将拥有不可预测/紧密耦合的代码?
    class A {
        Ra f(Pa x) { ... }
    }
    
    class B extends A {
        @Override
        Rb f(Pb x) { ... }
    }