Java初始化理解與總結(jié)

Java的初始化可以分為兩個部分:
(a)類的初始化
(b)對象的創(chuàng)建
(a)類的初始化


**一辕坝、概念介紹: ** 一個類(class)要被使用必須經(jīng)過裝載堕油,連接螟蒸,初始化這樣的過程政溃。

  • 在裝載階段,類裝載器會把編譯形成的class文件載入內(nèi)存,創(chuàng)建類相關(guān)的Class對象翼抠,這個Class對象封裝了我們要使用的類的類型信息咙轩。
  • 連接階段又可以分為三個子步驟:驗(yàn)證、準(zhǔn)備和解析阴颖。
  • 驗(yàn)證就是要確保java類型數(shù)據(jù)格式 的正確性活喊,并適于JVM使用。
  • 準(zhǔn)備階段量愧,JVM為靜態(tài)變量分配內(nèi)存空間钾菊,并設(shè)置默認(rèn)值,注意偎肃,這里是設(shè)置默認(rèn)值煞烫,比如說int型的變量會被賦予默認(rèn)值0 。在這個階段累颂,JVM可能還會為一些數(shù)據(jù)結(jié)構(gòu)分配內(nèi)存滞详,目的是提高運(yùn)行程序的性能,比如說方法表喘落。
  • 解析過程就是在類型的常量池中尋找類茵宪、接口最冰、字段和方法的符號引用瘦棋,把這些符號引用替換成直接引用。這個階段可以被推遲到初始化之后暖哨,當(dāng)程序運(yùn)行的過程中真正使用某個符號引用的時候 再去解析它赌朋。
  • 類的初始化:
  • 初始化類,是指初始化static靜態(tài)變量和執(zhí)行static靜態(tài)代碼塊篇裁。
  • 初始化接口沛慢,是指初始化定義在該接口中的filed。

二达布、類的初始化條件:
類會在首次被“主動使用”時執(zhí)行初始化团甲,以下情況第一次發(fā)生之前類會被初始化:

  1. 創(chuàng)建類的實(shí)例;
  2. 調(diào)用類的靜態(tài)方法黍聂;
  3. 調(diào)用類的靜態(tài)變量躺苦,并且該變量不是一個常變量
  4. 為類的靜態(tài)字段賦值产还;
  5. 在頂層類中執(zhí)行assert語句匹厘;(?)
  6. 調(diào)用類Class及包java.lang.reflect中的某些反射方法脐区;

JLS嚴(yán)格的說明:在任何其他的情況下愈诚,都不會對類或接口進(jìn)行初始化。

三、類的初始化規(guī)則:

  1. 類初始化時炕柔,該類的父類將首先被初始化酌泰,此過程一直遞歸到 java.lang.Object為止。但是父類實(shí)現(xiàn)的接口并不會被初始化匕累。
class Parent implements J{
    { System.out.println("父類初始化塊"); }  
    static{
        System.out.println("父類靜態(tài)初始化塊");  
    }
}
class Child extends Parent implements I{
    { System.out.println("子類初始化塊"); }  
    static{
        System.out.println("子類靜態(tài)初始化塊");  
    }
}
interface I {  
    int i = Test.out("interface : i", 1);  
}  
interface J {  
    int j = Test.out("interface : j", 2);  
}  
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        new Child();
    }
}
接口只有被用到時才會被初始化
輸出: 
父類靜態(tài)初始化塊
子類靜態(tài)初始化塊
父類初始化塊
子類初始化塊
  • 接口初始化時宫莱,只會初始化該接口本身,并不會初始化它的父接口哩罪。
interface I {  
    int i = Test.out("interface : i", 1);  
    int ii = Test.out("interface : ii", 11);  
}  
interface J extends I{  
    int j = Test.out("interface : j", 2);  
    int jj = Test.out("interface : jj", 22);  
}  
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        System.out.println(J.j);  
    }
}
輸出:
interface : j=2
interface : jj=22
2
  • 如果類的初始化是由于訪問靜態(tài)域而觸發(fā)授霸,那么只有真正定義該靜態(tài)域的類才被初始化,而不會觸發(fā)超類的初始化或者子類的初始化即使靜態(tài)域被子類或子接口或者它的實(shí)現(xiàn)類所引用际插。
    示例1:(如上所述)
class Parent{
    static int p = 10;
    static{
        System.out.println("父類靜態(tài)初始化塊");  
    }
}
class Child extends Parent{ 
    static int c = 20; 
    static{
        System.out.println("子類靜態(tài)初始化塊");  
    }
} 
public class Test { 
    public static void main(String [] args){
        System.out.println(Child.p);    //靜態(tài)域p被子類引用
    }
}
父類靜態(tài)初始化塊
10

示例2:(滿足類的初始化條件碘耳,父類也會被初始化,與示例1不同)

public class Test { 
    public static void main(String [] args){
        System.out.println(Child.c); 
    }
}
父類靜態(tài)初始化塊
子類靜態(tài)初始化塊
20
  • 如果一個靜態(tài)變量是編譯時常量框弛,則對它的引用不會引起定義它的類的初始化辛辨。
    示例1:
class Parent{
    static{
        System.out.println("父類靜態(tài)初始化塊");  
    }
}
class Child extends Parent{
    static final int x = 2005;  
    static{
        System.out.println("子類靜態(tài)初始化塊");  
    }
} 
public class Test { 
    public static void main(String [] args){
        System.out.println(Child.x); 
    }
}
輸出:
2005

示例2:(I.i是一個編譯時常量,因此它不會引起I被初始化。)

interface I {  
    int i = 1;  
    int ii = Test.out("ii", 2);  
}  
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        System.out.println(I.i);  
    }
}
1
  • 初始化類是指初始化static靜態(tài)變量和執(zhí)行static靜態(tài)代碼塊瑟枫,所以只會進(jìn)行一次斗搞。
    初始化接口也只會進(jìn)行一次。
    示例1:
class Child extends Parent{ 
    static int c = 20; 
    static{
        System.out.println("子類靜態(tài)初始化塊");  
    }
} 
public class Test { 
    public static void main(String [] args){
        System.out.println(Child.c); 
        System.out.println(Child.c); 
    }
}
父類靜態(tài)初始化塊
子類靜態(tài)初始化塊
20
20

示例2:

interface J{   
    int j = Test.out("j", 3);  
    int jj = Test.out("jj", 4);  
}    
public class Test { 
    static int out(String s, int i) {  
        System.out.println(s + "=" + i);  
        return i;  
    }  
    public static void main(String [] args){
        System.out.println(J.j);  
        System.out.println(J.j);  
    }
}
j=3
jj=4
3
3

(b)對象創(chuàng)建過程中的Java初始化

一. 對象的創(chuàng)建過程總結(jié)

假設(shè)有個名為Dog的類:

  1. 當(dāng)首次創(chuàng)建類型為Dog的對象時慷妙,或者Dog類的靜態(tài)方法/靜態(tài)域首次被訪問時僻焚,java解釋器必須查找類路徑,以定位Dog.class文件膝擂。
  2. 然后載入Dog.class(這將創(chuàng)建一個Class對象)虑啤,有關(guān)靜態(tài)初始化的所有動作都會執(zhí)行。因此架馋,靜態(tài)初始化只在class對象首次加載的時候進(jìn)行一次狞山。
  3. 當(dāng)用new Dog()創(chuàng)建對象的時候,首先將在堆上為Dog對象分配足夠的存儲空間叉寂。
  4. 這塊存儲空間會被清零萍启,這就自動地將Dog對象中的所有基本類型數(shù)據(jù)都設(shè)置成了默認(rèn)值(對數(shù)字來說就是0,對布爾型與字符型也相同)屏鳍,而引用則被設(shè)置成了null勘纯。
  5. 執(zhí)行所有出現(xiàn)于字段定義處的初始化動作。
  6. 執(zhí)行構(gòu)造器孕蝉。
    ---《Thinking in java》

二. 對象創(chuàng)建過程中初始化順序
父靜態(tài)成員>子靜態(tài)成員>父普通成員初始化>父構(gòu)造>子普通成員初始化>子構(gòu)造.
( 靜態(tài)初始化塊以靜態(tài)變量對待)

  • 示例1:
public class Test { 
    public static void main(String [] args){
        new Child();
    }
}
class Parent{
    { 
        System.out.println("父類普通成員初始化塊"); 
    }  
    static{
        System.out.println("父類靜態(tài)成員及初始化塊");
    }
    
    public Parent(){
        System.out.println("父類構(gòu)造函數(shù)"); 
    }
}
class Child extends Parent{
    { 
        System.out.println("子類普通成員初始化塊"); 
    }  
    static{
        System.out.println("子類靜態(tài)成員及初始化塊");
    }
    
    public Child(){
        super();
        System.out.println("子類構(gòu)造函數(shù)"); 
    }
}
父類靜態(tài)成員及初始化塊
子類靜態(tài)成員及初始化塊
父類普通成員初始化塊
父類構(gòu)造函數(shù)
子類普通成員初始化塊
子類構(gòu)造函數(shù)
  • 示例2:(證明 父構(gòu)造>子普通成員初始化>子構(gòu)造)
public class Test { 
    public static void main(String [] args){
        new Child();
    }
}
class Parent{
    public Parent(){
        System.out.println("父類構(gòu)造函數(shù)"); 
        System.out.println("子類成員變量 height:" + ((Child)this).height);
    }
}
class Child extends Parent{
    public int height= 20;
    { 
        System.out.println("子類非靜態(tài)成員初始化塊"); 
        System.out.println("子類成員變量 height:" + this.height);
    }  
    
    public Child(){
        super();
        System.out.println("子類構(gòu)造函數(shù)"); 
    }
}
父類構(gòu)造函數(shù)
子類成員變量 height:0
子類非靜態(tài)成員初始化塊
子類成員變量 height:20
子類構(gòu)造函數(shù)

三. 對象創(chuàng)建過程的說明

  1. 靜態(tài)域的初始化是在類的初始化期間屡律,非靜態(tài)域的初始化時在類的實(shí)例創(chuàng)建期間。這意味這靜態(tài)域初始化在非靜態(tài)域之前降淮。
  • 非靜態(tài)域通過構(gòu)造器初始化超埋,子類在做任何初始化之前構(gòu)造器會隱含地調(diào)用父類的構(gòu)造器搏讶,這保證了父類非靜態(tài)實(shí)例變量初始化早于子類。
  • 調(diào)用Class的類成員變量時霍殴,構(gòu)造函數(shù)和成員變量不會執(zhí)行
public class Test { 
    public static void main(String [] args){
        System.out.println(Parent.a); 
    }
}
class Parent{
    public static int a = 10;
    {
        System.out.println("父類普通成員初始化塊");
    }
    public Parent(){
        System.out.println("父類構(gòu)造函數(shù)"); 
    }
}
輸出:10
  • 在類的內(nèi)部媒惕,變量定義的先后順序決定了初始化的順序;
    即使變量定義散布于方法定義之間,它們?nèi)詴谌魏畏椒ǎò?gòu)造器)被調(diào)用之前得到初始化来庭。
public class Test { 
    public static void main(String [] args){
        new Parent(); 
    }
}
class Parent{
    {
        System.out.println("普通成員初始化塊1");
    }
    public Parent(){
        System.out.println("構(gòu)造函數(shù)"); 
    }
    {
        System.out.println("普通成員初始化塊2");
    }
}
普通成員初始化塊1
普通成員初始化塊2
構(gòu)造函數(shù)
  • 多態(tài)情況下的對象初始化
public class Test {    
  public static void main(String [] args){
      Parent parent = new Child();
  }
}
class Parent{
  { 
      System.out.println("父類普通成員初始化塊"); 
  }  
  static{
      System.out.println("父類靜態(tài)成員及初始化塊");
  }

  public Parent(){
      System.out.println("父類構(gòu)造函數(shù)"); 
  }
}
class Child extends Parent{
  { 
      System.out.println("子類普通成員初始化塊"); 
  }  
  static{
      System.out.println("子類靜態(tài)成員及初始化塊");
  }

  public Child(){
      super();
      System.out.println("子類構(gòu)造函數(shù)"); 
  }
}
父類靜態(tài)成員及初始化塊
子類靜態(tài)成員及初始化塊
父類普通成員初始化塊
父類構(gòu)造函數(shù)
子類普通成員初始化塊
子類構(gòu)造函數(shù)

可見多態(tài)情況下的初始化與示例1中繼承情況下的初始化是一樣的妒蔚,因?yàn)槎际莿?chuàng)建的子類的實(shí)例。

  • 程序的執(zhí)行過程月弛,即Java虛擬機(jī)執(zhí)行Test 的靜態(tài)方法main肴盏,這也會引起Test 類的初始化。(理解面向?qū)ο蠖敲嫦蜻^程)
public class Test {    
    public static void main(String [] args){
      System.out.println("Test- main");
    }
  
    static{
      System.out.println("靜態(tài)成員及初始化塊");
    }
}
靜態(tài)成員及初始化塊
Test- main

2015/8

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帽衙,一起剝皮案震驚了整個濱河市菜皂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌厉萝,老刑警劉巖恍飘,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谴垫,居然都是意外死亡章母,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門翩剪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來乳怎,“玉大人,你說我怎么就攤上這事肢专∥杷粒” “怎么了焦辅?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵博杖,是天一觀的道長。 經(jīng)常有香客問我筷登,道長剃根,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任前方,我火速辦了婚禮狈醉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惠险。我一直安慰自己苗傅,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布班巩。 她就那樣靜靜地躺著渣慕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逊桦,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天眨猎,我揣著相機(jī)與錄音,去河邊找鬼强经。 笑死睡陪,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匿情。 我是一名探鬼主播兰迫,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼炬称!你這毒婦竟也來了逮矛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤转砖,失蹤者是張志新(化名)和其女友劉穎须鼎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體府蔗,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晋控,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了姓赤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赡译。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖不铆,靈堂內(nèi)的尸體忽然破棺而出蝌焚,到底是詐尸還是另有隱情,我是刑警寧澤誓斥,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布只洒,位于F島的核電站,受9級特大地震影響劳坑,放射性物質(zhì)發(fā)生泄漏毕谴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一距芬、第九天 我趴在偏房一處隱蔽的房頂上張望涝开。 院中可真熱鬧,春花似錦框仔、人聲如沸舀武。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽银舱。三九已至衷旅,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間纵朋,已是汗流浹背柿顶。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工基协, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匈勋,地道東北人鲁僚。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓盔夜,卻偏偏與公主長得像墓卦,于是被迫代替她去往敵國和親部逮。 傳聞我的和親對象是個殘疾皇子泻帮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法固棚,類相關(guān)的語法藏澳,內(nèi)部類的語法仁锯,繼承相關(guān)的語法,異常的語法翔悠,線程的語...
    子非魚_t_閱讀 31,581評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理业崖,服務(wù)發(fā)現(xiàn),斷路器蓄愁,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 小編費(fèi)力收集:給你想要的面試集合 1.C++或Java中的異常處理機(jī)制的簡單原理和應(yīng)用双炕。 當(dāng)JAVA程序違反了JA...
    八爺君閱讀 4,573評論 1 114
  • (一)Java部分 1、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,071評論 0 62
  • 寒雨連江夜入?yún)谴樽ィ矫魉涂统焦赂窘铩B尻栍H友如相問,一片冰心在玉壺丹拯。 唐代詩人王昌齡的一首《芙蓉樓送辛漸》站超,將“冰心”...
    玉天下閱讀 392評論 0 1