前言
在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 實例檢查做到為那兩個字段賦值
主站蜘蛛池模板:
志丹县|
沁水县|
湄潭县|
县级市|
锦州市|
同仁县|
通化市|
临猗县|
攀枝花市|
泰来县|
海兴县|
余庆县|
卓尼县|
武清区|
偃师市|
神木县|
禹州市|
临沭县|
鄂尔多斯市|
海宁市|
壤塘县|
开封市|
无为县|
弥勒县|
中阳县|
渝北区|
唐山市|
天峨县|
峡江县|
轮台县|
桓仁|
和林格尔县|
龙口市|
临湘市|
四川省|
凤阳县|
夏津县|
綦江县|
岑溪市|
永胜县|
类乌齐县|