致電a.print()
打印4
因爲polymorphism。所調用的方法取決於a
的運行時間類型,即B
。它叫什麼時候並不重要;多態總是適用的。
兩次,B
的print
方法被調用。一次來自A
的構造函數,它由B
中的默認構造函數調用。另一次是您在main
的明確電話。
第一次打印得到0
而不是4
的原因是因爲在調用print
時,A
仍在構建中。也就是說,A
構造函數仍在執行中。在超類構造函數返回之前,子類中沒有任何東西被初始化,甚至沒有變量初始值設定項。在超類構造函數完成後,但在子類構造函數的其餘部分完成之前,值4
被分配。因爲變量初始值設定項尚未運行,所以缺省值0
(對於對象boolean
和null
,將爲false
)爲第一次打印時的值i
。
此順序由列出的JLS, Section 12.5:
就在到新創建的對象的引用被作爲結果返回時,所指示的構造被處理使用下面的過程來初始化新的對象:
將構造函數的參數分配給此構造函數調用的新創建的參數變量。
如果此構造函數以相同類中另一個構造函數的顯式構造函數調用(第8.8.7.1節)開頭(使用此參數),則計算參數並使用這五個相同的步驟來遞歸構造函數調用。如果構造函數的調用突然完成,則此過程由於同樣的原因突然完成;否則,請繼續執行步驟5.
此構造函數不是以相同類中另一個構造函數的顯式構造函數調用開始的(使用此方法)。如果此構造函數用於Object以外的類,則此構造函數將以顯式或隱式調用超類構造函數(使用super)開始。評估參數並使用這五個相同的步驟遞歸地處理該超類構造函數的調用。如果構造函數的調用突然完成,那麼出於同樣的原因,此過程會突然完成。否則,請繼續步驟4。
執行實例初始化和實例變量初始化這個類,分配實例變量初始化的值,以相應的實例變量,在左到右的順序在它們文本地出現在源代碼班上。如果執行這些初始化程序中的任何一個都會導致異常,則不會執行進一步的初始化程序,並且此過程突然以相同的異常完成。否則,請繼續步驟5.
執行此構造函數的其餘部分。如果該執行突然完成,則此過程因相同原因突然完成。否則,此過程正常完成。
(粗體重點煤礦)
這就是爲什麼它是一個壞主意,打電話可以從構造函數中覆蓋的方法的例子。子類狀態尚未初始化。
'a.print'不引用類A,a只引用類型'B'的類型'A'的對象。 – Geinmachi
這是爲什麼我們應該避免構造函數中的多態方法的很好的例子。爲了避免這些問題,只能使用私有,靜態或最終的方法。 – Pshemo