一旦一個(gè)類被裝載吏垮、連接和初始化障涯,它就隨時(shí)可以被使用。程序可以訪問(wèn)它的靜態(tài)字段膳汪,調(diào)用它的靜態(tài)方法唯蝶,或者創(chuàng)建它的實(shí)例。作為Java程序員有必要了解Java對(duì)象的生命周期遗嗽。
類實(shí)例化
在Java程序中粘我,類可以被明確或隱含地實(shí)例化。明確的實(shí)例化類有四種途徑:
- 明確調(diào)用
new
痹换。 - 調(diào)用
Class
或者java.lang.reflect.Constructor
對(duì)象的newInstance
方法征字。 - 調(diào)用任何現(xiàn)有對(duì)象的
clone
。 - 通過(guò)
java.io.ObjectInputStream.getObject()
反序列化娇豫。
隱含的實(shí)例化:
- 可能是保存命令行參數(shù)的
String
對(duì)象匙姜。 - 對(duì)于Java虛擬機(jī)裝載的每個(gè)類,都會(huì)暗中實(shí)例化一個(gè)Class對(duì)象來(lái)代表這個(gè)類型
- 當(dāng)Java虛擬機(jī)裝載了在常量池中包含
CONSTANT_String_info
入口的類的時(shí)候冯痢,它會(huì)創(chuàng)建新的String
對(duì)象來(lái)表示這些常量字符串氮昧。 - 執(zhí)行包含字符串連接操作符的表達(dá)式會(huì)產(chǎn)生新的對(duì)象框杜。
Java編譯器為它編譯的每個(gè)類至少生成一個(gè)實(shí)例初始化方法。在Java class文件中袖肥,這個(gè)方法被稱為<init>
咪辱。針對(duì)源代碼中每個(gè)類的構(gòu)造方法,Java編譯器都會(huì)產(chǎn)生一個(gè)<init>()
方法椎组。如果累沒(méi)有明確的聲明任何構(gòu)造方法梧乘,編譯器會(huì)默認(rèn)產(chǎn)生一個(gè)無(wú)參數(shù)的構(gòu)造方法,它僅僅調(diào)用父類的無(wú)參構(gòu)造方法庐杨。
一個(gè)<init>()
中可能包含三種代碼:調(diào)用另一個(gè)<init>()
选调、實(shí)現(xiàn)對(duì)任何實(shí)例變量的初始化、構(gòu)造方法體的代碼灵份。
如果構(gòu)造方法明確的調(diào)用了同一個(gè)類中的另一個(gè)構(gòu)造方法(this()
)仁堪,那么它對(duì)應(yīng)的<init>()
由兩部分組成:
- 一個(gè)同類的
<init>()
的調(diào)用。 - 實(shí)現(xiàn)了對(duì)應(yīng)構(gòu)造方法的方法體的字節(jié)碼填渠。
在它對(duì)應(yīng)的
<init>()
方法中不會(huì)有父類的<init>()
弦聂,但不代表不會(huì)調(diào)用父類的<init>()
,因?yàn)?code>this()中也會(huì)調(diào)用父類<init>()
如果構(gòu)造方法不是通過(guò)一個(gè)this()
調(diào)用開(kāi)始的氛什,而且這個(gè)對(duì)象不是Object
莺葫,<init>()
則有三部分組成:
- 一個(gè)父類的
<init>()
調(diào)用。如果這個(gè)類是Object
,則沒(méi)有這個(gè)部分 - 任意實(shí)例變量初始化方法的字節(jié)碼枪眉。
- 實(shí)現(xiàn)了對(duì)應(yīng)構(gòu)造方法的方法體的字節(jié)碼捺檬。
如果構(gòu)造方法明確的調(diào)用父類的構(gòu)造方法super()
開(kāi)始,它的<init>()
會(huì)調(diào)用對(duì)應(yīng)父類的<init>()
贸铜。比如堡纬,如果一個(gè)構(gòu)造方法明確的調(diào)用super(int,String)
開(kāi)始,對(duì)應(yīng)的<init>()
會(huì)從調(diào)用父類的<init>(int,String)
方法開(kāi)始蒿秦。如果構(gòu)造方法沒(méi)有明確地從this()
或super()
開(kāi)始烤镐,對(duì)應(yīng)的<init>()
默認(rèn)會(huì)調(diào)用父類的無(wú)參<init>()
。
垃圾收集和對(duì)象的終結(jié)
程序可以明確或隱含的為對(duì)象分配內(nèi)存棍鳖,但不能明確的釋放內(nèi)存炮叶。一個(gè)對(duì)象不再為程序引用,虛擬機(jī)必須回事那部分內(nèi)存渡处。
卸載類
在很多方面镜悉,Java虛擬機(jī)中類的生命周期和對(duì)象的生命周期很相似。當(dāng)程序不再使用某個(gè)類的時(shí)候骂蓖,可以選擇卸載它們积瞒。
類的垃圾收集和卸載值所以在Java虛擬機(jī)中很重要,是因?yàn)镴ava程序可以在運(yùn)行時(shí)通過(guò)用戶自定義的類裝載器裝載類型來(lái)動(dòng)態(tài)的擴(kuò)展程序登下。所有被裝載的類型都在方法區(qū)占據(jù)內(nèi)存空間茫孔。
Java虛擬機(jī)通過(guò)判斷類是否在被引用來(lái)進(jìn)行垃圾收集叮喳。判斷動(dòng)態(tài)裝載的類的Class
實(shí)例在正常的垃圾收集過(guò)程中是否可觸及有兩種方式:
- 如果程序保持非
Class
實(shí)例的明確引用。 - 如果在堆中還存在一個(gè)可觸及的對(duì)象缰贝,在方法區(qū)中它的類型數(shù)據(jù)指向一個(gè)
Class
實(shí)例馍悟。