在上一篇文章中講述了java對(duì)象的銷毀和垃圾回收器的工作方式,這篇文章將講下java對(duì)象的創(chuàng)建,這對(duì)我們平時(shí)的開(kāi)發(fā)也有一定的幫助。
假如存在一個(gè)名為User的類,User的成員變量有靜態(tài)的和非靜態(tài)的。
1:當(dāng)創(chuàng)建User類的對(duì)象或調(diào)用其靜態(tài)成員變量或靜態(tài)方法時(shí),java編譯器會(huì)先定位User.class
2:java裝載機(jī)ClassLoader加載User.class,此時(shí)會(huì)初始化其靜態(tài)成員變量。因此,靜態(tài)成員變量只會(huì)在Class首次被裝載時(shí)初始化一次
3:通過(guò)new User()創(chuàng)建對(duì)象,此時(shí)會(huì)在堆區(qū)域?yàn)槠浞峙浯鎯?chǔ)空間
4:該存儲(chǔ)空間會(huì)被清零,自動(dòng)為User對(duì)象的成員變量設(shè)置默認(rèn)值(基本類型成員變量,如int會(huì)被賦值0),如果有引用,設(shè)置為null
5:執(zhí)行成員變量的初始化(例如int times = 9)
6:調(diào)用構(gòu)造方法,完成類的完整初始化
還有一點(diǎn)需要注意,就是出現(xiàn)繼承時(shí)的構(gòu)造方法的調(diào)用順序
如果User繼承基類BaseBean,那么在創(chuàng)建User對(duì)象,上述的第4步走完之后,順序會(huì)發(fā)生變化
5:調(diào)用基類BaseBean的構(gòu)造方法
6:執(zhí)行User成員變量的初始化
7:調(diào)用User的構(gòu)造函數(shù)
初始化不當(dāng)會(huì)產(chǎn)生的問(wèn)題
下面這個(gè)程序就是由于構(gòu)造方法初始化不當(dāng)引起問(wèn)題的典型??聪旅鎯蓚€(gè)類的定義:




最后是以上程序的執(zhí)行結(jié)果。
分析:在User對(duì)象分配堆區(qū)域,并對(duì)區(qū)域清零后,此時(shí)成員變量都被賦予了默認(rèn)值,
1:調(diào)用基類構(gòu)造函數(shù),打印BaseBean
2:調(diào)用init()方法,由于基類的此方法被User重寫(xiě),所以此時(shí)調(diào)用User對(duì)象的init()方法,但此時(shí)name變量還未被初始化,只是被賦予了默認(rèn)值而已,因此打印的是User name:null(此處很驚訝,是造成我們要討論的問(wèn)題的原因)
3:完成成員變量初始化和調(diào)用User構(gòu)造函數(shù)
問(wèn)題分析:User子類在未完全初始化的情況下訪問(wèn)其成員變量,造成null的出現(xiàn)
總結(jié)
在定義構(gòu)造函數(shù)時(shí),盡量快速完成初始化,盡量不要調(diào)用其他方法,因?yàn)槟悴恢雷宇愂欠駮?huì)重寫(xiě)被調(diào)用的方法,就像上面的例子,在init()中就會(huì)出現(xiàn)null的情況,如果此時(shí)直接使用name就會(huì)報(bào)空指針。如果非要調(diào)用方法,可以將方法定義為final 或者private(默認(rèn)也會(huì)被final修飾)類型,避免被子類重寫(xiě),產(chǎn)生問(wèn)題。