java基礎(chǔ)-父類子類初始化順序簡(jiǎn)析

首先,關(guān)于父類子類靜態(tài)成員的初始化順序,是一個(gè)筆試面試經(jīng)常出現(xiàn)的問題,這個(gè)是一個(gè)基礎(chǔ),每一個(gè)寫java代碼的工程師都需要搞清楚的問題。但是,搞清楚歸搞清楚,平時(shí)寫代碼的時(shí)候,正常情況下,都不會(huì)這樣去寫,就類似于經(jīng)常考到的 i++ ++i 這樣的問題,平時(shí),不會(huì)這樣寫,也不能這樣寫,代碼審核過不了的。

這批文章針對(duì)的是剛接觸java不久的新同學(xué)。

首先看下面的代碼

Father類

public class Father {

    private int x;
    static{
        System.out.println("father-static");
    }

    {
        x = 11;
        System.out.println("father-member,x = "+x);
    }

    Father(){
        x = 21;
        System.out.println("father-constructor,x = "+x);
    }

}

Son類,繼承Father

public class Son extends Father {
    private  int y;
    static{
        System.out.println("son-static");
    }

    {
        y = 10;
        System.out.println("son-member,y="+y);
    }

    Son(){
        y = 20;
        System.out.println("son-constructor,y="+y);
    }
}

然后寫一個(gè)執(zhí)行類

public class Init {
    public static void main(String[] args) {
         Son mys = new Son();
         System.out.println("over");
    }
}

執(zhí)行結(jié)果

father-static
son-static
father-member,x = 11
father-constructor,x = 21
son-member,y=10
son-constructor,y=20
over

通過結(jié)果來看,非常清晰。

  1. 初始化父類的靜態(tài)塊。這一步實(shí)際意思就是初始化父類使用static修飾的成員。
  2. 初始化子類的靜態(tài)塊。
  3. 執(zhí)行父類的變量初始化。
  4. 執(zhí)行子類的變量初始化。
  5. 執(zhí)行父類的構(gòu)造器。
  6. 執(zhí)行子類的構(gòu)造器。

這個(gè)過程,看著代碼理解一下就ok了。
首先,初始化靜態(tài)部分,這個(gè)是類加載器執(zhí)行的,首先會(huì)把這部分執(zhí)行了。
在初始化初始化子類靜態(tài)變量之前,會(huì)先初始化父類的靜態(tài)變量,如果子類使用了父類的靜態(tài)變量,這能保證父類的靜態(tài)變量是初始化好的。
上面這一步,是在加載類的時(shí)候執(zhí)行的,是在new之前。
然后,執(zhí)行new了,會(huì)去執(zhí)行類的構(gòu)造函數(shù)。
子類的構(gòu)造函數(shù)的第一行,是調(diào)用父類的構(gòu)造函數(shù)。
可能有同學(xué)說,我沒有調(diào)用啊。
對(duì)于無參構(gòu)造函數(shù),編譯器會(huì)自動(dòng)增加一句 super()
實(shí)際代碼應(yīng)該是這樣

    Son(){
        super();
        y = 20;
        System.out.println("son-constructor,y="+y);
    }

而另一個(gè)java基本常識(shí)就是,如果我們沒有寫構(gòu)造函數(shù),編譯器會(huì)自動(dòng)增加一個(gè)無參構(gòu)造函數(shù)
所以,上面寫的5,6步,每次new一個(gè)類的時(shí)候,都是執(zhí)行了的,只是如果沒有我們寫的構(gòu)造器,就會(huì)去執(zhí)行一個(gè)空的無參構(gòu)造器,編譯器自動(dòng)加上去的。

super() 這一句,會(huì)被自動(dòng)加上去,我們無法測(cè)試,我們可以給Father類的構(gòu)造器,增加一個(gè)參數(shù),讓他沒有無參構(gòu)造器。

public class Father {

    private int x;
    static{
        System.out.println("father-static");
    }

    {
        x = 11;
        System.out.println("father-member,x = "+x);
    }

    Father(int i){
        x = 21;
        System.out.println("father-constructor,x = "+x);
    }

}

這個(gè)時(shí)候,去看Son的代碼,會(huì)發(fā)現(xiàn),構(gòu)造器上面有錯(cuò)誤提示。


image.png

提示內(nèi)容是

There is no default constructor available in 'com.demo.test1.init.Father'

意思就是,沒有默認(rèn)的構(gòu)造器,也就是沒有無參構(gòu)造器。
解決辦法很簡(jiǎn)單,調(diào)用super的時(shí)候,把參數(shù)給進(jìn)去。

 Son(){
        super(1);
        y = 20;
        System.out.println("son-constructor,y="+y);
    }

可以試一下,在ide里面,把super(1)放到y(tǒng)=20之后,看看報(bào)錯(cuò)不。

咱們?cè)俎垡晦?br> 首先,類加載器在加載類的時(shí)候,會(huì)先初始化類的靜態(tài)成員變量或者靜態(tài)塊
這么做的目的,是為了保證,有些地方直接使用類靜態(tài)成員,這個(gè)時(shí)候,是不會(huì)實(shí)例化這個(gè)類的,也就是不會(huì)觸發(fā)執(zhí)行構(gòu)造器。

然后,實(shí)例化一個(gè)類,也就是new一個(gè)類的時(shí)候,會(huì)先初始化普通成員變量及代碼塊,然后再執(zhí)行構(gòu)造器,這是為了保證構(gòu)造器能夠正常使用這些成員變量,這是一個(gè)類的初始化過程,如果,有父類,那么先對(duì)父類執(zhí)行這個(gè)過程,再執(zhí)行子類。

最后,編譯器為我們做了很多事情,例如,沒有構(gòu)造器的時(shí)候,加一個(gè)默認(rèn)無參的構(gòu)造器;在子類的構(gòu)造器中,默認(rèn)的去調(diào)用父類無參構(gòu)造器,等等,這些,都是需要知道的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容