2016-04-27 58 views
1

今天我們在工作中遇到了一個有趣的案例,涉及Java中的方法調用。想象一下以下內容:強制調用專門的方法

class Bar {} 

class ExtendedBar extends Bar {} 

class Foo { 
    void doFoo(Bar bar) {} 
} 

class ExtendedFoo extends Foo { 
    void doFoo(ExtendedBar exBar) {} 
} 

現在你有ExtendedBar一個實例,並要撥打doFoo()ExtendedFoo一個實例。在我們的測試中,運行時間選擇Foo s doFoo(Bar)實現,而不是doFoo(ExtendedBar)ExtendedFoo

當然這個問題有一個簡單的方法 - 我們只需要將doFoo重命名爲其他的東西 - 但是,如果不重命名該方法,某種程度上可能會讓我們感到震驚,因爲它保留了方法的名稱這裏用在強大的傳統語境中。

+1

提示:'doFoo(ExtendedBar)'* does ** not ***'Override''doFoo(Bar)'。 *名稱*不是真正的問題,方法有不同的簽名。 –

+1

如果「_你有一個ExtendedBar的實例,並且你想對ExtendedFoo_的一個實例調用doFoo()」,那麼它應該選擇'doFoo(ExtendedBar)'。看到這個:http://ideone.com/sJCZ3W – Hackerdarshi

+0

@Hackerdarshi嗯,你是對的,那麼我想我有一個不同的問題(在這裏運行Android ART,而不是本機JVM)。感謝您清除那個(並且ideone被加入書籤:)) –

回答

2

我不認爲有辦法做到這一點直線,因爲你不是覆蓋的方法,但陰影它。您可以通過在其上添加一個@Override來輕鬆斷言。請注意,如果你這樣做與返回類型,將很好地工作:

class Foo { 
    Bar doFoo() { return null; } 
} 

class ExtendedFoo extends Foo { 
    @Override 
    ExtendedBar doFoo() { return null; } 
} 

但只要你改變參數,這是一個不同的簽名

你在這種情況下可以做的是使用通用性,我猜。

class Foo<BAR extends Bar> { 
    void doFoo(BAR bar) {} 
} 

class ExtendedFoo extends Foo<ExtendedBar> { 
    @Override 
    void doFoo(ExtendedBar exBar) {} 
} 

現在,因爲你實際上並妥善首要該方法中,JRE會妥善解決的方法調用並調用專業之一。

0

除了別人說過的話:你爲什麼在這裏試試......簡直是錯的。

定義一個繼承層次需要更多的思考,而不僅僅是把「extends Something」放在你的類上。你想確保你瞭解Liskov Substitution Principle

在您的情況:一個子類應該從未限制任何在一些基類中定義的參數類型的方法。你可以限制返回類型(例如返回Long時基類返回Number);但對於「輸入」參數,只能擴展(允許數字,當基類使用Long時)。

正確的OO建模思想意味着:在使用Foo對象的任何一段源代碼中,您應該能夠用ExtendedFoo對象代替Foo對象。你的建議違反了這條規則。

+0

絕對理解 - 我個人不會自己提出這樣的想法,如果我不會在DI的背景下被迫做這樣醜陋的事情我正在使用的庫(Dagger2)。 –