新聞中心
在Java中,一個(gè)對(duì)象在可以被使用之前必須要被正確地初始化,這一點(diǎn)是Java規(guī)范規(guī)定的。在實(shí)例化一個(gè)對(duì)象時(shí),JVM首先會(huì)檢查相關(guān)類型是否已經(jīng)加載并初始化,如果沒(méi)有,則JVM立即進(jìn)行加載并調(diào)用類構(gòu)造器完成類的初始化。在類初始化過(guò)程中或初始化完畢后,根據(jù)具體情況才會(huì)去對(duì)類進(jìn)行實(shí)例化。本文試圖對(duì)JVM執(zhí)行類初始化和實(shí)例化的過(guò)程做一個(gè)詳細(xì)深入地介紹,以便從Java虛擬機(jī)的角度清晰解剖一個(gè)Java對(duì)象的創(chuàng)建過(guò)程。

公司主營(yíng)業(yè)務(wù):成都做網(wǎng)站、成都網(wǎng)站制作、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。成都創(chuàng)新互聯(lián)公司是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。成都創(chuàng)新互聯(lián)公司推出肅北免費(fèi)做網(wǎng)站回饋大家。
一個(gè)類及其對(duì)象初始化的過(guò)程
什么時(shí)候需要初始化一個(gè)類
首次創(chuàng)建某個(gè)對(duì)象時(shí):
Dog dog = new Dog();
首次訪問(wèn)某個(gè)類的靜態(tài)方法或者靜態(tài)字段時(shí):
Dog.staticFields;
Java 解釋器就會(huì)去找類的路徑,定位已經(jīng)編譯好的 Dog.class 文件。
獲得類的資源
然后 jvm 就會(huì)載入 Dog.class,生成一個(gè) class 對(duì)象。這個(gè)時(shí)候如果有靜態(tài)的方法或者變量,靜態(tài)初始化動(dòng)作都會(huì)被執(zhí)行。這個(gè)時(shí)候要注意啦,靜態(tài)初始化在程序運(yùn)行過(guò)程中只會(huì)在 Class 對(duì)象首次加載的時(shí)候運(yùn)行一次。這些資源都會(huì)放在 jvm 的方法區(qū)。
方法區(qū)又叫靜態(tài)區(qū),跟堆一樣,被所有的線程共享。
方法區(qū)中包含的都是在整個(gè)程序中永遠(yuǎn)唯一的元素,包含所有的 class 和 static 變量。
初始化對(duì)象 *Dog dog = new Dog()*
第一次創(chuàng)建 Dog 對(duì)象先執(zhí)行上面的一二步 在堆上為 Dog 對(duì)象分配足夠的存儲(chǔ)空間,所有屬性和方法都被設(shè)置成默認(rèn)值(數(shù)字為 0,字符為 null,布爾為 false,而所有引用被設(shè)置成 null) 執(zhí)行構(gòu)造函數(shù)檢查是否有父類,如果有父類會(huì)先調(diào)用父類的構(gòu)造函數(shù),這里假設(shè) Dog 沒(méi)有父類,執(zhí)行默認(rèn)值字段的賦值即方法的初始化動(dòng)作。 執(zhí)行構(gòu)造函數(shù)。
有父類情況下的初始化
假設(shè): Dog extends Animal
1.執(zhí)行第一步,找出 Dog.class 文件,接著在加載過(guò)程中發(fā)現(xiàn)他有一個(gè)基類(通過(guò) extends 關(guān)鍵字),于是先執(zhí)行 Animal 類的第一二步,加載其靜態(tài)變量和方法,加載結(jié)束之后再加載子類 Dog 的靜態(tài)變量和方法。 如果 Animal 類還有父類就以此類推,最終的基類叫做根基類。 注意:因?yàn)樽宇惖?static 初始化可能會(huì)依賴于父類的靜態(tài)資源,所以要先加載父類的靜態(tài)資源。
2.接著要 new Dog 對(duì)象,先為 Dog 對(duì)象分配存儲(chǔ)空間 -> 到 Dog 的構(gòu)造函數(shù) -> 創(chuàng)建默認(rèn)的屬性。這里其構(gòu)造函數(shù)里面的第一行有個(gè)隱含的 super(),即父類構(gòu)造函數(shù),所以這時(shí)會(huì)跳轉(zhuǎn)到父類 Animal 的構(gòu)造函數(shù)。
Java 會(huì)幫我們完成構(gòu)造函數(shù)的補(bǔ)充,Dog 實(shí)際隱式的構(gòu)造函數(shù)如下:
Dog() {
//創(chuàng)建默認(rèn)的屬性和方法
//調(diào)用父類的構(gòu)造函數(shù)super()(可顯式寫(xiě)出)
//對(duì)默認(rèn)屬性和方法分別進(jìn)行賦值和初始化
}
3、父類 Animal 執(zhí)行構(gòu)造函數(shù)前也是分配存儲(chǔ)空間 -> 到其構(gòu)造函數(shù) -> 創(chuàng)建默認(rèn)的屬性 -> 發(fā)現(xiàn)挖槽我已經(jīng)沒(méi)有父類了,這個(gè)時(shí)候就給它的默認(rèn)的屬性賦值和方法的初始化。
4、接著執(zhí)行構(gòu)造函數(shù)余下的部分,結(jié)束后跳轉(zhuǎn)到子類 Dog 的構(gòu)造函數(shù)。
5、子類 Dog 對(duì)默認(rèn)屬性和方法分別進(jìn)行賦值和初始化,接著完成構(gòu)造函數(shù)接下來(lái)的部分。
一、為什么要執(zhí)行父類 Animal 的構(gòu)造方法才繼續(xù)子類 Dog 的屬性及方法賦值?
因?yàn)樽宇?Dog 的非靜態(tài)變量和方法的初始化有可能使用到其父類 Animal 的屬性或方法,所以子類構(gòu)造默認(rèn)的屬性和方法之后不應(yīng)該進(jìn)行賦值,而要跳轉(zhuǎn)到父類的構(gòu)造方法完成父類對(duì)象的構(gòu)造之后,才來(lái)對(duì)自己的屬性和方法進(jìn)行初始化。
這也是為什么子類的構(gòu)造函數(shù)顯示調(diào)用父類構(gòu)造函數(shù) super() 時(shí)要強(qiáng)制寫(xiě)在第一行的原因,程序需要跳轉(zhuǎn)到父類構(gòu)造函數(shù)完成父類對(duì)象的構(gòu)造后才能執(zhí)行子類構(gòu)造函數(shù)的余下部分。
二、為什么對(duì)屬性和方法初始化之后再執(zhí)行構(gòu)造函數(shù)其他的部分?
因?yàn)闃?gòu)造函數(shù)中的顯式部分有可能使用到對(duì)象的屬性和方法。
Tips:其實(shí)這種初始化過(guò)程都是為了保證后面資源初始化用到的東西前面的已經(jīng)初始化完畢了。很厲害,膜拜 Java 的父親們。
說(shuō)了這么多還是來(lái)個(gè)例子吧。
這里注意 main 函數(shù)也是一個(gè)靜態(tài)資源,執(zhí)行 Dog 類的 main 函數(shù)就是調(diào)用 Dog 的靜態(tài)資源。
實(shí)例
//父類Animal
class Animal {
/*8、執(zhí)行初始化*/
private int i = 9;
protected int j;
/*7、調(diào)用構(gòu)造方法,創(chuàng)建默認(rèn)屬性和方法,完成后發(fā)現(xiàn)自己沒(méi)有父類*/
public Animal() {
/*9、執(zhí)行構(gòu)造方法剩下的內(nèi)容,結(jié)束后回到子類構(gòu)造函數(shù)中*/
System.out.println("i = " + i + ", j = " + j);
j = 39;
}
/*2、初始化根基類的靜態(tài)對(duì)象和靜態(tài)方法*/
private static int x1 = print("static Animal.x1 initialized");
static int print(String s) {
System.out.println(s);
return 47;
}
}
//子類 Dog
public class Dog extends Animal {
/*10、初始化默認(rèn)的屬性和方法*/
private int k = print("Dog.k initialized");
/*6、開(kāi)始創(chuàng)建對(duì)象,即分配存儲(chǔ)空間->創(chuàng)建默認(rèn)的屬性和方法。
* 遇到隱式或者顯式寫(xiě)出的super()跳轉(zhuǎn)到父類Animal的構(gòu)造函數(shù)。
* super()要寫(xiě)在構(gòu)造函數(shù)第一行 */
public Dog() {
/*11、初始化結(jié)束執(zhí)行剩下的語(yǔ)句*/
System.out.println("k = " + k);
System.out.println("j = " + j);
}
/*3、初始化子類的靜態(tài)對(duì)象靜態(tài)方法,當(dāng)然mian函數(shù)也是靜態(tài)方法*/
private static int x2 = print("static Dog.x2 initialized");
/*1、要執(zhí)行靜態(tài)main,首先要加載Dog.class文件,加載過(guò)程中發(fā)現(xiàn)有父類Animal,
*所以也要加載Animal.class文件,直至找到根基類,這里就是Animal*/
public static void main(String[] args) {
/*4、前面步驟完成后執(zhí)行main方法,輸出語(yǔ)句*/
System.out.println("Dog constructor");
/*5、遇到new Dog(),調(diào)用Dog對(duì)象的構(gòu)造函數(shù)*/
Dog dog = new Dog();
/*12、運(yùn)行main函數(shù)余下的部分程序*/
System.out.println("Main Left");
}
}
測(cè)試輸出結(jié)果為:
static Animal.x1 initialized
static Dog.x2 initialized
Dog constructor
i = 9, j = 0
Dog.k initialized
k = 47
j = 39
Main Left
新聞名稱:Java 對(duì)象初始化具體步驟
當(dāng)前URL:http://m.fisionsoft.com.cn/article/dhjsphj.html


咨詢
建站咨詢
