如何防止超类调用overriden子类方法?

Ant*_*tte 2 java polymorphism inheritance overriding

我刚刚遇到这个问题,它让我感到意外.

超一流:

public class Foo {

    @Override
    public String toString(){
        return String.format("Result = %s", calculate());
    }
    public double calculate(){
        return 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

子类:

public class Bar extends Foo {
    @Override
    public String toString(){
        return String.format("%s", super.toString());
    }
    @Override
    public double calculate(){
        return 123.456;
    }
}
Run Code Online (Sandbox Code Playgroud)

司机:

public static void main(String[] args) {
    System.out.println(new Bar().toString());
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下我想要1 的输出是我得到的输出123.456

如何阻止Foo toString()调用Bar calculate()

use*_*ica 6

如果您不想让子类重写calculate,请标记它final:

public final double calculate() {
    ...
}
Run Code Online (Sandbox Code Playgroud)

如果您想让它们覆盖calculate,但您不想在此特定位置使用覆盖,请将实现calculate放在私有方法中并使用私有版本:

public double calculate() {
    return _calculate();
}
private double _calculate() {
    return 1.0;
}
@Override
public String toString(){
    return String.format("Result = %s", _calculate());
}
Run Code Online (Sandbox Code Playgroud)

  • 你不明白规格或规格是错误的. (4认同)

Bee*_*ope 5

你不能直接这样做 - 你已经被覆盖了calculate(),因为你有一个Bar对象,所以Bar.calculate()calculate()使用时它总是会被调用1.如果是其他任何方式,那么制作合理的OoO设计会非常困惑和困难!

如果你真的想要所描述的行为,通常的解决方案就是Foo.toString()调用一个不可覆盖的(例如,privatefinal)辅助方法来实现你所拥有的逻辑Foo.calculate().然后你就可以放心toString(),即使Foo被覆盖也总是以同样的方式行事2.然后,你可以Foo.calculate()通过调用这个辅助方法来实现,取悦DRY神.

当然,您可能会问自己,您的班级设计是否有问题.上面建议的更改意味着你有一个不寻常的情况,即使在对象上Foo.calculate()也用于toString()调用Bar,但直接调用calculate()将导致Bar行为.所以你的toString()输出将与任何打电话的人calculate()都看到不一致.这很少是你想要的.


1除了可以在内部Bar显式调用超类calculate()方法之外super.calculate().这对你没有帮助,因为你想要做的是,在超类中,阻止虚拟调用calculate()进入其他任何地方.

2当然,如果有人覆盖,toString()那么所有投注都将被取消.final如果你想避免这种情况,你总是可以做到.

  • 没有看到实际的规格就很难说.请注意,如果重写`Bar.toString()`,你当然可以使用`super().calculate()`来实现`Foo.calculate()`的术语.你不能通过调用`super.toString()来很好地做到这一点 - 但是有一些非常丑陋的方法.例如,你可以以某种方式传达给`Bar.calculate()``那的toString()`是呼叫者在这种情况下,委托给`Foo.calculate()`使用`super` - 例如,使用TLS,检查堆栈,或在对象中设置字段.尽管如此......这仍然非常可怕...... @AnthonyAudette (2认同)