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並在輸出中附加其附加信息 –

相關問題