Java初始化小析

Java里有局部變量、實(shí)例變量、靜態(tài)變量,它們的初始化表現(xiàn)也不盡相同。下面來(lái)總結(jié)一下。

局部變量

void f() {
    int i;
    i++; // Error -- i not initialized
}

局部變量應(yīng)該是最簡(jiǎn)單的情景,在一個(gè)方法內(nèi)定義一個(gè)變量,如果不為它賦予初始值,編譯器則會(huì)報(bào)錯(cuò)。所以聲明局部變量時(shí)必須同時(shí)賦予其初始值。

實(shí)例變量

每一個(gè)實(shí)例變量都會(huì)保證有一個(gè)初始值。

public class InitialiValues {

    boolean t;
    char c;
    byte b;
    short s;
    int i;
    long l;
    float f;
    double d;

    InitialiValues initialization;

    void printInitialValues() {
        System.out.println("boolean    " + t);
        System.out.println("char    " + c + "");
        System.out.println("byte    " + b);
        System.out.println("short    " + s);
        System.out.println("int    " + i);
        System.out.println("long    " + l);
        System.out.println("float    " + f);
        System.out.println("double    " + d);
    }

    public static void main(String[] args) {
        new InitialiValues().printInitialValues();
    }
}

/* Output */

boolean    false
char    null
byte    0
short    0
int    0
long    0
float    0.0
double    0.0
reference    null

即使不指定初始值,實(shí)例變量會(huì)自動(dòng)擁有一個(gè)默認(rèn)初始值

構(gòu)造器初始化

public class Counter {

    int i;
    public Counter() {
        System.out.println("before: " +  i);
        i = 7;
        System.out.println("after: " + i);
    }

    public static void main(String[] args) {
        new Counter();
    }
}

//Output:
before: 0
after: 7

我們可以利用構(gòu)造器來(lái)進(jìn)行初始化,但是在構(gòu)造器進(jìn)行初始化之前,counter已經(jīng)自動(dòng)初始化了一次。

初始化順序

在一個(gè)類中,成員變量的初始化順序是由變量在類中定義的順序決定的,而且總會(huì)在類中的任何方法被調(diào)用前就已經(jīng)初始化好了。

public class Window {

    Window(int marker) {
        System.out.println("Window(" + marker + ")");
    }

}

public class House {

    Window w1 = new Window(1);
    House() {
        System.out.println("House()");
        w3 = new Window(33);
    }
    Window w2 = new Window(2);
    void f() {
        System.out.println("f()");
    }
    Window w3 = new Window(3);

}

public static void main(String[] args) {
        House h = new House();
        h.f();
}

//Output:

Window(1)
Window(2)
Window(3)
House()
Window(33)
f()

可以看到,雖然Window對(duì)象的定義被打散了,但確實(shí)是等到所有的Windown變量初始化完成后,才執(zhí)行構(gòu)造器。

繼承關(guān)系下的初始化順序

在上面的基礎(chǔ)上加上一個(gè)子類繼承關(guān)系后,情況又會(huì)怎樣?

public class SonHouse extends House{

    Window sonWindow = new Window(4);

    SonHouse() {
        sonWindow = new Window(44);
        }
    }
}

public static void main(String[] args) {
        House h = new SonHouse();
        h.f();
}

//Output:

Window(1)
Window(2)
Window(3)
House()
Window(33)
Window(4)
Window(44)
f()

事實(shí)證明,孝順是一種優(yōu)良品質(zhì),先讓父類初始化完成后,再輪到子類

static變量的初始化時(shí)機(jī)

public class Bowl {

    Bowl(int marker) {
        System.out.println("Bowl(" + marker + ")");
    }

    void f1(int marker) {
        System.out.println("f1(" + marker + ")");
    }
}



public class Table {

    static Bowl bowl1 = new Bowl(1);
    Table() {
        System.out.println("Table()");
        bowl2.f1(1);
    }

    void f2(int marker) {
        System.out.println("f2(" + marker + ")");
    }
    static Bowl bowl2 = new Bowl(2);
}

public class Cupboard {

    Bowl bowl3 = new Bowl(3);
    static Bowl bowl4 = new Bowl(4);

    Cupboard() {
        System.out.println("Cupboard");
        bowl4.f1(2);
    }

    void f3(int marker) {
        System.out.println("f3(" + marker + ")");
    }
    static Bowl bowl5 = new Bowl(5);
}

public class StaticInitialization {

    public static void main(String[] args) {
        System.out.println("Creating new Cupboard() in main");
        new Cupboard();

        System.out.println("Creating new Cupboard() in main");
        new Cupboard();

        table.f2(1);
        cupboard.f3(2);
    }

    static Table table = new Table();
    static Cupboard cupboard = new Cupboard();
}

//Output:

Bowl(1)
Bowl(2)
Table()
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
Cupboard
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard
f1(2)
Creating new Cupboard() in main
Bowl(3)
Cupboard
f1(2)
f2(1)
f3(2)

可以看出,static變量總是最先初始化。要注意的是,static變量只會(huì)初始化一次,而且只會(huì)在第一次需要用到的時(shí)候才進(jìn)行
初始化。然后才到 non-static變量初始化

就像上述示例,要執(zhí)行main(),StaticInitialization類就需要被加載,然后其static變量 table和cupboad這個(gè)時(shí)候
同樣需要被加載上,又因?yàn)樗鼈兌加衧tatic Bowl 變量,所以這是Bowl類也同時(shí)被加載。所以這些類在執(zhí)行main方法前都已經(jīng)
加載好了。

其實(shí),學(xué)習(xí)過(guò)JVM話就會(huì)知道,一個(gè)class只有在第一次需要引用的時(shí)候才會(huì)被加載,以后需要用到這個(gè)class就直接從classloader
獲取不需要加載了。而 static變量的初始化就是在class第一次被加載到classloader的時(shí)候發(fā)生的。所以不難理解為什么static變量
只會(huì)初始化一次。

總結(jié)

  1. 對(duì)于實(shí)例變量,按照聲明的順序逐個(gè)初始化,先父類,后子類

  2. static 成員在類第一次被加載時(shí)進(jìn)行初始化,并且只初始化這么一次

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 34,855評(píng)論 18 399
  • 父類 static 塊 1 執(zhí)行 父類 靜態(tài)成員staticSam1初始化 父類 靜態(tài)成員staticSam2初始...
    YCix閱讀 1,408評(píng)論 0 0
  • 一:java概述:1,JDK:Java Development Kit,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工...
    ZaneInTheSun閱讀 2,823評(píng)論 0 11
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,711評(píng)論 19 139
  • 昨天在思考,如何正確做一個(gè)專家,經(jīng)過(guò)反思和觀察踐行,得出一個(gè)真正的專家應(yīng)該具備兩個(gè)維度的能力 - 專業(yè)認(rèn)知能力強(qiáng) ...
    逄格亮閱讀 282評(píng)論 0 0

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