[英]Java inconsistent inheritance mechanics?
我想我們已經在這篇文章中討論了這個問題,這里繼承Java簡單說明
但由於這里的例子有點簡單,我想澄清的意思不同,我會試一試。
首先,討論兩個類:
public class SuperClass{
SuperClass() {
foo();
}
public void foo() {
System.out.println("Super.foo()");
}
public static void main(String[] args) {
SuperClass tn = new DerivedClass();
tn.foo();
}
}
public class DerivedClass extends SuperClass{
String i;
TrickyB() {
i = "aksjhdf";
}
public void foo() {
System.out.println("In derived.foo() --> " + i);
}
}
我(至少我認為)理解多態的概念,我知道為什么在調用時調用DerivedClass.foo()
new DerivedClass();
我在這看到一個不一致的地方:
在我們調用DerivedClass的DerivedClass
,SuperClass的SuperClass
被隱式調用(所以說作為Derived c'tor的第一行)。
所以在Super c'tor中, DerivedClass
沒有完全初始化,這使得使用這個類沒用。 這一點反映在該計划的輸出中
In derived.foo() --> null
In derived.foo() --> aksjhdf
第一行反映了我的困惑:
為什么調用DerivedClass.foo()
? 對象還沒有准備好,所以用它做任何事情在我眼里都是胡說八道。
任何人都可以向我解釋原因。 我認為這絕對違反直覺。
順便說一下:我SuperClass.foo()
應該調用SuperClass.foo()
,因為正如我所說,使用“未准備”對象沒有任何意義。
另一方面:我想起來了。 這對我來說沒有任何意義,當我在SuperClass的時候, DerivedClass.foo()
被調用!
在我的情況下,我如何調用SuperClass.foo()
?
為什么調用DerivedClass.foo()? 對象還沒有准備好,所以用它做任何事情在我眼里都是胡說八道。
沒有。該對象已經創建。 構造函數不創建對象,只是初始化它們。 該對象由new
運算符在此創建。
我原以為要調用SuperClass.foo()
正如已經解釋過的那樣,並不是沒有創建對象。 它已經存在了。 並且該調用將調用重寫的方法。 這就是為什么你永遠不應該從構造函數調用重寫方法 。 你會看到意想不到的行為。
SuperClass
對任何派生類都一無所知。
嗯,它不需要知道。 方法調用調用派生類方法的事實與超類是否知道子類無關。 將在運行時根據圖片中的實際對象確定將調用的實際方法。 因為在這里,對象的類型是DerivedClass
,在該方法DerivedClass
如果存在的話將被調用。
在我的情況下,我如何調用SuperClass.foo()?
你沒有。 這就是重點。 瀏覽我鏈接的帖子,逐步解釋。
與C ++不同,Java在分配時,在運行任何構造函數之前設置對象的運行時類型。 這就是初始化期間發生多態行為的原因。
在受控情況下,此行為有時很有用。 但是,在大多數情況下,避免使用它是一個好主意,因為您正在將未初始化的對象泄露給類外部的代碼(通過虛方法中的this
引用)。 您應盡可能嘗試從構造函數中調用私有(或最終)方法。
Why is DerivedClass.foo() called?
因為這是Java語言設計。 開發人員可以自己確保繼承層次結構中的不變類,而不是語言。
How would I call SuperClass.foo() in my case?
從派生類: super.foo();
DerivedClass.foo()在DerivedClass中調用。 為對象本身調用foo()。 通過繼承,這也可以等於SuperClass.foo()。 但是,由於多態性也可能不同。 如果你明確地想要來自SuperClass的foo(),那么調用super.foo()。 順便說一下,因為DerivedClass.foo()依賴於i,所以你應該首先初始化i。
正如Rohit所說,不應該從構造函數中調用重寫的方法(或更確切地說,可以覆蓋的方法)。 這是一個方法:
public class SuperClass{
SuperClass() {
privateFoo();
}
public void foo() {
privateFoo();
}
private void privateFoo() { // cannot be overridden since it's private
System.out.println("Super.foo()");
}
}
使foo
方法只是一個調用私有版本的單行方法。 當然,如果它有參數和/或返回值,你可以包括那些。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.