【13】Java基礎:java中的靜態代碼塊,靜態變量,靜態方法

一、Java虛擬機內存的五個區域:

這裏寫圖片描述

(1)、方法區:在java的虛擬機中有一塊專門用來存放已經加載的類信息、常量、靜態變量以及方法代碼的內存區域,

(2)、常量池:常量池是方法區的一部分,主要用來存放常量和類中的符號引用等信息。

(3)、堆區:用於存放類的對象實例。

(4)、棧區:也叫java虛擬機棧,是由一個一個的棧幀組成的後進先出的棧式結構,棧楨中存放方法運行時產生的局部變量、方法出口等信息。
當調用一個方法時,虛擬機棧中就會創建一個棧幀存放這些數據,當方法調用完成時,棧幀消失,如果方法中調用了其他方法,則繼續在棧頂創建新的棧楨。

二、類的生命週期

當我們編寫一個java的源文件後,經過編譯會生成一個後綴名爲class的文件,這種文件叫做字節碼文件,只有這種字節碼文件才能夠在java虛擬機中運行,java類的生命週期就是指一個class文件從加載到卸載的全過程。

一個java類的完整的生命週期會經歷加載、連接、初始化、使用、和卸載五個階段,當然也有在加載或者連接之後沒有被初始化就直接被使用的情況,如圖所示:

這裏寫圖片描述

三、靜態變量

其中靜態代碼在類的初始化階段被初始化。而非靜態代碼則在類的使用階段(也就是實例化一個類的時候)纔會被初始化。

可以將靜態變量理解爲類變量(與對象無關),而實例變量則屬於一個特定的對象。

靜態變量有兩種情況:
(1)、靜態變量是基本數據類型,這種情況下在類的外部不必創建該類的實例就可以直接使用
(2)、靜態變量是一個引用。這種情況比較特殊,主要問題是由於靜態變量是一個對象的引用,那麼必須初始化這個對象之後才能將引用指向它。因此如果要把一個引用定義成static的,就必須在定義的時候就對其對象進行初始化。

四、靜態方法

與類變量不同,方法(靜態方法與實例方法)在內存中只有一份,無論該類有多少個實例,都共用一個方法。

靜態方法與實例方法的不同主要有:
(1)、靜態方法可以直接使用,而實例方法必須在類實例化之後通過對象來調用。
在外部調用靜態方法時,可以使用“類名.方法名”或者“對象名.方法名”的形式。實例方法只能使用後面這種方式。
(2)、靜態方法只允許訪問靜態成員。而實例方法中可以訪問靜態成員和實例成員。
(3)、靜態方法中不能使用this(因爲this是與實例相關的)。

五、靜態代碼塊

靜態代碼塊主要用於類的初始化。它只執行一次,並在main函數之前執行。
靜態代碼塊的特點主要有:
(1)、靜態代碼塊會在類被加載時自動執行。
(2)、靜態代碼塊只能定義在類裏面,不能定義在方法裏面。
(3)、靜態代碼塊裏的變量都是局部變量,只在塊內有效。
一個類中可以定義多個靜態代碼塊,按順序執行。
(4)、靜態代碼塊只能訪問類的靜態成員,而不允許訪問實例成員。

六、執行順序

實例化子類的時候,若此類未被加載過,首先加載是父類的類對象,然後加載子類的類對象,接着實例化父類,最後實例化子類,若此類被加載過,不再加載父類和子類的類對象。接下來是加載順序,當加載類對象時,首先執行靜態屬性初始化,然後執行靜態塊,當實例化對象時,首先執行實例塊,然後執行構造方法,至於各靜態塊、實例塊之間的執行順序,是按代碼的先後順序。

DEMO:
A.java:


public class A {

    private static String staticStr = getStaticStr();

    private String str = getStr();

    static {
        System.out.println("A的靜態塊");
    }

    private static String staticStr2 = getStaticStr2();

    {
        System.out.println("A的實例塊");
    }

    public A() {
        System.out.println("A的構造方法");
    }

    private static String getStaticStr() {
        System.out.println("A的靜態屬性初始化");
        return null;
    }

    private static String getStaticStr2() {
        System.out.println("A的靜態屬性初始化2");
        return null;
    }

    private String getStr() {
        System.out.println("A的實例屬性初始化");
        return null;
    }
}

B.java

class B extends A {

    private static String staticStr = getStaticStr();

    private String str = getStr();

    static {
        System.out.println("B的靜態塊");
    }

    {
        System.out.println("B的實例塊");
    }

    public B() {
        System.out.println("B的構造方法");
    }

    private static String getStaticStr() {
        System.out.println("B的靜態屬性初始化");
        return null;
    }

    private String getStr() {
        System.out.println("B的實例屬性初始化");
        return null;
    }

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

打印如下:

A的靜態屬性初始化
A的靜態塊
A的靜態屬性初始化2
B的靜態屬性初始化
B的靜態塊
A的實例屬性初始化
A的實例塊
A的構造方法
B的實例屬性初始化
B的實例塊
B的構造方法
A的實例屬性初始化
A的實例塊
A的構造方法
B的實例屬性初始化
B的實例塊
B的構造方法

參考致謝:
(1)、詳解java類的生命週期
(2)、 java中靜態的代碼塊,靜態變量,靜態方法
(3)、java中static

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章