2017-04-03 73 views
2

我刚刚遇到了这个问题,它让我吃了一惊。如何防止超类调用overriden子类方法?

超一流:

public class Foo { 

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

子类:

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

司机:

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

我在这种情况下希望的输出是1 我得到的输出是123.456

如何阻止Foo的toString()致电Bar的calculate()

+1

您既可以创建'Foo'的实例而不是'Bar',或者简单地不重写'Foo#calculate'。 –

+0

我正在处理的代码需要这个结构,按照规范 –

+1

你可以在Bar#calculate'里面调用'super.calculate()'吗? –

回答

6

如果你不想让子类覆盖calculate可言,它标记final

public final double calculate() { 
    ... 
} 

如果你想让他们覆盖calculate,但你不想使用这个覆盖特定的位置,放calculate实施的私有方法,并使用专用版本:

public double calculate() { 
    return _calculate(); 
} 
private double _calculate() { 
    return 1.0; 
} 
@Override 
public String toString(){ 
    return String.format("Result = %s", _calculate()); 
} 
+0

我遇到的问题是我正在编写的规范要求重写,否则我只会使用类似这样的解决方法。 –

+4

您不明白规格或规格错误。 –

+0

根据我教授的记录,后者很可能是正确的。我会推迟你提出的明显解决方案,如果她试图为它取消标记,将它用作参考。 有没有我可以查询的文献,这将明确证实这一点? –

5

你不能直接这样做 - 你已经覆盖calculate()因为你有一个Bar对象它始终是Bar.calculate(),使用calculate()时调用。如果以其他方式制作合理的OoO设计,将会非常混乱和困难!

如果真要如所描述的行为,通常的解决方法是简单地具有Foo.toString()呼叫实现您在Foo.calculate()具有逻辑非覆盖的(例如,privatefinal)辅助方法。那么你可以放心,toString()总是表现相同的方式,即使Foo被覆盖。然后,你可以通过调用这个帮助器方法来实现Foo.calculate(),取悦DRY神。

当然,你可能会问自己,你的班级设计是否有问题。上述建议的更改意味着您有异常情况,Foo.calculate()正用于toString()呼叫,即使在Bar对象上,但直接调用calculate()将导致Bar行为。因此,您的toString()输出将与任何呼叫calculate()的人看到的内容不一致。这很少是你想要的。


除了使用它是可能的,Bar,显式调用使用super.calculate()calculate()方法。这对你并没有帮助,因为你想要做的是在超类中阻止calculate()的虚拟呼叫去其他地方。

当然,如果有人重写toString(),那么所有投注都将关闭。如果你想避免这种情况,你总是可以使它成为final

+0

是的,我的老师的规格问题是,它明确声明使用此结构并覆盖toString() 下面的评论@ user2357112的答案已经证实,她的规格是这里实际上是畸形的。 –

+2

很难说没有看到实际的规格。请注意,如果您重写'Bar.toString()',那么您可以通过使用'super()。calculate()''来实现'Foo.calculate()'的条款。你不能很好地通过调用'super.toString()'来完成它 - 但是有一些非常难看的方法。例如,你可以通过某种方式与'Bar.calculate()'通信,'toString()'是调用者,在这种情况下,使用'super'委托给'Foo.calculate()' - 例如使用TLS检查堆栈,或者在对象中设置一个字段。虽然这一切都相当可怕.... @AnthonyAudette – BeeOnRope

+0

我使用的任何解决方案都必定是丑陋的,因为规范是老师的问题,所以我很想留下逻辑错误。 为了清晰起见,我会解释她想要的(错综复杂的)结构。 Abstract ProjectInvoice>劳工扩展ProjectInvoice> LabourAndMaterials扩展劳工> LabourAndMaterialsAndEquipment扩展LabourAndMaterials。 ProjectInvoice包含抽象方法calculateCost() 每个子类都会覆盖计算成本并将超类的计算添加到它自己的计算中。 每个都会覆盖toString并在输出中附加其附加信息 –

相关问题