Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/327.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:重写子类中的抽象方法_Java_Oop - Fatal编程技术网

Java:重写子类中的抽象方法

Java:重写子类中的抽象方法,java,oop,Java,Oop,我真的应该知道这一点,但出于某种原因,我不理解以下内容 My abstract类包含以下抽象方法: protected abstract RuleDTO createRowToBeCloned(RuleDTO ruleDTO); 我还有另一门课,如下所示: EvaluationRuleDTO extends from RuleDTO 然后,在我的抽象类的子类中,我有以下实现,这是不允许的,因为“必须重写或实现超类型方法”: 但是,允许以下情况: protected EvaluationRul

我真的应该知道这一点,但出于某种原因,我不理解以下内容

My abstract类包含以下抽象方法:

protected abstract RuleDTO createRowToBeCloned(RuleDTO ruleDTO);
我还有另一门课,如下所示:

EvaluationRuleDTO extends from RuleDTO
然后,在我的抽象类的子类中,我有以下实现,这是不允许的,因为“必须重写或实现超类型方法”:

但是,允许以下情况:

protected EvaluationRuleDTO createRowToBeCloned(RuleDTO ruleDTO) {
我意识到这可能是一个基本问题,但我有点困惑。为什么我可以在重写的方法中返回RuleDTO的子类,但不能传入子类


感谢

这是因为当重写方法时,必须使用相同类型或更通用(更宽)类型作为参数类型,而不是更窄的类型

想想看。如果您可以使用更窄的类型重写方法,您会破坏多态性功能,您同意吗?因此,这样做,您将打破JB Nizet在其回答中所说的错误。

Java1.5有类型,这就是它有效的原因

子类方法的返回类型R2可能不同于超类 方法的返回类型R1,但R2应该是R1的子类型。即。, 子类可以返回类型可以是超类返回类型的子类型


Java允许覆盖的返回类型协方差,因此可以将覆盖的返回类型指定为更派生的类型。但是,Java不允许覆盖的参数类型协方差

前者安全的原因是,您返回的对象至少具有派生类型较少的功能,因此依赖该事实的客户端仍然能够正确使用返回的对象

不过,这些论点并非如此。如果是合法的,用户可以调用抽象方法并传入派生程度较低的类型(因为这是在抽象类上声明的类型),但是派生重写可能会尝试以派生程度较高的类型(不是)访问参数,从而导致错误


理论上,Java可以允许参数类型相反,因为这是类型安全的:如果重写的方法只需要较少的派生参数,则不能意外地使用不存在的方法或字段。不幸的是,这目前还不可用。

您正在打破Liskov原则:超类所能做的一切,子类都必须能够做到。超类声明一个接受任何类型RuleDTO的方法。但在子类中,您只接受EvaluationRuleDTO的实例。如果您执行以下操作,会发生什么情况

RuleDTO rule = new EvaluationRuleDTO();
rule.createRowToBeCloned(new RuleDTO());
EvaluationRuleDTO是RuleDTO,因此它必须履行RuleDTO定义的合同


子类中的方法可能会返回EvaluationRuleDTO的实例而不是RuleDTO,因为契约将返回RuleDTO,而EvaluationRuleDTO是RuleDTO。

在早期java中不是这样,但在java 5.0中有所更改

同一类中不能有两个方法的签名仅在返回类型上不同。在J2SE5.0发布之前,类不能重写从超类继承的方法的返回类型也是事实。在本技巧中,您将了解J2SE 5.0中允许协变返回类型的一个新特性。这意味着子类中的方法可能返回一个对象,该对象的类型是该方法返回的类型的子类,该方法在超类中具有相同的签名。此功能消除了过度类型检查和强制转换的需要

资料来源:


这意味着重写方法的返回类型将是重写方法的返回类型的子类型。

请参阅以下代码:

class A {
    A foo(A a) {
        return new A();
    }
}

class B extends A {
    @Override
    // Returning a subtype in the overriding method is fine,
    // but using a subtype in the argument list is NOT fine!
    B foo(B b) {
        b.bar();
        return new B();
    }
    void bar() {
        // B specific method!
    }
}
是的,好的,B是A,但如果有人这样做会发生什么:

B b = new B();
b.foo(new A());
A没有bar方法。。这就是为什么参数不能是被重写方法中参数类型的子类型

在重写方法中返回A或B是可以的。下面的代码段将很好地编译和运行

class A {
    A foo(A a) {
        return new B(); // B IS AN A so I can return B!
    }
}

class B extends A {
    @Override
    B foo(A b) {
        return new B(); // Overridden method returns A and 
                        // B IS AN A so I can return B!
    }

    public static void main(String[] args) {
        A b = new B();
        final A foo = b.foo(new B());
        // I can even cast foo to B!
        B cast = (B) foo;
    }
}

引用您的回答“您必须使用相同类型或更通用(更广泛)的类型作为参数类型,而不是更窄的类型”,这不适用于Java。虽然从Liskov原理的角度来看这是正确的,但方法参数类型在Java中必须是不变的。这正是我所要寻找的。非常感谢。“子类中的方法可能返回EvaluationRuleDTO的实例,而不是RuleDTO”=>我在这里没有看到任何问题,这在Java中实际上是允许的。(可能不是在2012年吧?)这将很好地编译:。你几乎总是有很好的答案,但我一点也不懂。@KorayTugay我也看不出有什么问题。这就是这句话的重点:解释子类中的方法可以返回更具体的内容。
class A {
    A foo(A a) {
        return new B(); // B IS AN A so I can return B!
    }
}

class B extends A {
    @Override
    B foo(A b) {
        return new B(); // Overridden method returns A and 
                        // B IS AN A so I can return B!
    }

    public static void main(String[] args) {
        A b = new B();
        final A foo = b.foo(new B());
        // I can even cast foo to B!
        B cast = (B) foo;
    }
}