[英]Java inheritance not behaving as expected
需要以下上下文:這種編碼方式的目的是避免if
- else
語句和instanceof
。 這總是一個壞主意。
我有3個帶有以下簽名的類:
abstract class A {}
class B extends A {}
class C extends A {}
然后我有另一個具有以下結構的類:
class MyClass {
private final A model;
public MyClass(A m) {
this.model = m;
}
public void doSomething() {
System.out.println(this.model instanceof C); //TRUE!!
execute(this.model);
}
private void execute(A m) {
System.out.println("noo");
}
private void execute(C m) {
System.out.println("yay");
}
}
最后是我主要內容:
public static void main(String... args) {
C mod = new C();
MyClass myClass = new MyClass(mod);
myClass.doSomething();
}
現在的問題; execute(C)方法永遠不會執行,它始終是execute(A)方法。 我該如何解決? 我無法將execute(A)方法的簽名更改為execute(B),因為這會在MyClass#doSomething上提示Java“無法解析方法execute(A)”。
方法重載在編譯時解決。 在編譯時, m
的類型為A
,因此execute(A m)
被執行。
另外,私有方法是不可覆蓋的。
解決方案是使用@OliverCharlesworth建議的Visitor模式。
您的代碼說明了對象的靜態和動態類型之間的區別。 靜態類型是編譯器已知的。 動態類型是運行時實際存在的內容。
您model
字段的靜態類型為A
:
private final A model;
也就是說,編譯器知道A
本身或其某些實現將被分配給model
。 編譯器一無所知,因此要在execute(A m)
和execute(C m)
之間進行選擇時,唯一的選擇就是execute(A m)
。 該方法基於對象的靜態類型進行解析。
另一方面, instanceof
了解動態類型。 它可以告訴您model
已設置為C
,因此在打印輸出中報告了true
。
您可以通過向A
添加方法並在B
和C
覆蓋該方法以路由至適當的execute
來解決此問題:
abstract class A {
public abstract void callExecute(MyClass back);
}
class B extends A {
public void callExecute(MyClass back) {
back.execute(this);
}
}
class C extends A {
public void callExecute(MyClass back) {
back.execute(this);
}
}
class MyClass {
private final A model;
public MyClass(A m) {
this.model = m;
}
public void doSomething() {
System.out.println(this.model instanceof C); //TRUE!!
model.callExecute(this.model);
}
public void execute(B m) {
System.out.println("noo");
}
public void execute(C m) {
System.out.println("yay");
}
}
請注意,這兩個實現都調用
back.execute(this);
然而,內部的執行B
具有this
類型的B
,和內部執行C
具有this
類型的C
,因此呼叫被路由到的不同的重載execute
的方法MyClass
。
我無法將
execute(A)
方法的簽名更改為execute(B)
還要注意,現在您也可以(並且應該)這樣做,因為基於this
類型對正確的重載執行了回調。
方法重載是編譯時的多態性。 因此,要調用方法execute(C)
您需要將模型定義為class C
。 最好在class A
定義方法execute()
並在子類中重寫它。
abstract class A {
abstract void execute();
}
class B extends A {
public void execute(){};
}
class C extends A {
public void execute(){};
}
接着:
class MyClass {
private final A model;
public void doSomething() {
model.execute();
}
使用多態性來避免if-else語句和instanceof檢查的更好的方法
您正在將C類型的對象作為構造函數中A類型的對象發送(您已經完成了轉換),並將其分配給A類型的引用(這將導致僅調用execute(A)方法)。您可以檢查是否object是C的實例,並根據結果調用所需的方法。 你可以這樣
public void doSomething(){
System.out.println(model instanceof C);
if (model instanceof C) execute((C)model);
else
execute(model);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.