前言
在Java中,一個對象在可以被使用之前必須要被正確地初始化,這一點是Java規范規定的。最近我發現了一個有趣的問題,這個問題的答案乍一看下騙過了我的眼睛。看一下這三個類:
package com.ds.test;public class Upper { String upperString; public Upper() { Initializer.initialize(this); }}package com.ds.test;public class Lower extends Upper { String lowerString = null; public Lower() { super(); System.out.println("Upper: " + upperString); System.out.println("Lower: " + lowerString); } public static void main(final String[] args) { new Lower(); }}package com.ds.test;public class Initializer { static void initialize(final Upper anUpper) { if (anUpper instanceof Lower) { Lower lower = (Lower) anUpper; lower.lowerString = "lowerInited"; } anUpper.upperString = "upperInited"; }}運行 Lower 這個類可以得到什么輸出?在這個極簡的例子中可以更容易地看到整個形勢,但是這個情形發生在現實中會有非常多的代碼分散一個人的注意力。
不管怎么樣,輸出是像這樣的:
Upper: upperInitedLower: null;
雖然小示例中使用了 String 類型,Initializer 類的實際代碼中有一個用于注冊的委托對象,與 Lower 類的功能是相同的 ― 至少 Lower 類是這個意圖。但由于某些原因在運行應用程序時沒有工作。取而代之的是,使用了默認路徑,委托對象沒有被設置 (null)。
現在稍微改變一下 Lower 的代碼:
package com.ds.test;public class Lower extends Upper { String lowerString; public Lower() { super(); System.out.println("Upper: " + upperString); System.out.println("Lower: " + lowerString); } public static void main(final String[] args) { new Lower(); }}現在的輸出是這樣的:
Upper: upperInitedLower: lowerInited
發現代碼中的區別了嗎?
是的,這個 lowerString 字段不再明確地設置為空。為什么這么做會有不同。不管怎樣參考類型字段(例如這里的 String )的默認值不是為空的嗎?當然是空的。事實證明,雖然這種微小的變化顯然不會以任何方式改變代碼行為,但是卻讓結果變的不同。
那么,到底發生了什么?當查看初始化順序的時候一切就變的清晰了:
1.main() 函數調用了 Lower 構造器。
2.Lower 的一個實例被準備好了。意味著所有的字段都被創建并且填充了默認值,例如,引用類型的默認值為空,布爾類型的默認值為 false 。在這個時候,任何的對字段的內聯賦值都沒有發生。
3.父類構造器被調用了。這是被語言的特性所強制執行的。所以在其他任何事發生之前,Upper 的構造器被調用了。
4.Upper 這個構造器運行并且指定了一個引用,指向 Initializer.initialize() 方法新創建的的實例。
5.Initializer 類為兩個字段( upperString 和 lowerString )附上新字符串。通過使用有點骯臟的 instanceof 實例檢查做到為那兩個字段賦值 
主站蜘蛛池模板:
翼城县|
怀远县|
隆昌县|
三亚市|
达尔|
富民县|
东兰县|
洪泽县|
灵寿县|
澄城县|
车致|
永安市|
兴义市|
保德县|
南城县|
贵州省|
阿克陶县|
旅游|
宁明县|
南乐县|
雅江县|
南郑县|
织金县|
汝城县|
仙桃市|
潢川县|
张家港市|
故城县|
富宁县|
扬州市|
大化|
乐清市|
孟津县|
黄冈市|
门源|
南京市|
乌兰察布市|
裕民县|
任丘市|
微博|
竹山县|