首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 類載入順序與記憶體佈局深度解析:靜態區塊、建構區塊、建構子執行時機

     編輯:Java 相關知識

Java 類從載入到物件建立,經歷嚴格的生命週期。本文詳細闡述類載入觸發條件、各成員在方法區與堆中的儲存位置、物件實例化的 9 個步驟,以及靜態區塊、建構區塊、建構子的執行順序差異。

一、類載入觸發時機

只有「主動使用」類才會觸發載入:

  1. 建立實例:new MyClass()
  2. 存取靜態成員:MyClass.staticField、MyClass.staticMethod()
  3. 啟動主類:java MyClass

「被動使用」(如存取常數、透過子類引用父類靜態欄位)不會觸發該類初始化。

二、類檔案載入內容與記憶體區域

載入時將 .class 位元碼存入方法區,非靜態成員變數(實例欄位)不會被載入:

類成員儲存區域備註
靜態變數方法區(靜態區)類變數,所有實例共享
靜態方法方法區(靜態區)
靜態區塊方法區(靜態區)類初始化時執行一次
非靜態方法方法區(非靜態區)含建構子,所有實例共享程式碼
建構區塊方法區(靜態區)編譯器複製進每個建構子
非靜態變數堆(實例內部)實例建立時分配

關鍵點:非靜態方法載入時只存程式碼,不建立實例;呼叫時需先有實例,JVM 透過 this 區分調用者。

三、物件實例化完整流程

Person p = new Person("zhangsan", 20);
  1. 堆疊分配 main 框架,建立引用變數 p。
  2. 載入 Person.class 至方法區(靜態成員、方法、區塊)。
  3. 執行靜態區塊與靜態變數顯式初始化(類初始化)。
  4. 堆中分配實例記憶體,取得位址。
  5. 實例變數預設初始化(0/null/false)。
  6. 實例變數顯式初始化(賦值語句)。
  7. 執行建構區塊(按宣告順序)。
  8. 執行對應建構子程式碼。
  9. 將堆位址賦給堆疊引用 p。

四、方法呼叫記憶體模型

實例方法

p.setName("lisi");
  1. 堆疊建立 setName 框架,含 this 與參數 name。
  2. this 指向堆中實例。
  3. 參數賦值,修改實例欄位。

靜態方法

Person.showCountry();
  1. 堆疊建立 showCountry 框架,含類引用 Person。
  2. 直接存取方法區靜態欄位。

五、三大區塊差異與執行順序

區塊類型用途執行時機執行次數
靜態區塊 static { }類初始化類載入時一次
建構區塊 { }實例通用初始化建構子前,每次 new每次建實例
建構子特定實例初始化建構區塊後每次建實例

六、程式碼驗證


class Person {
    private String name;
    private int age = 0;
    private static String country = "cn";

    Person(String name, int age) {
        this.name = name; this.age = age;
    }
    static { System.out.println("靜態區塊"); }
    { System.out.println(name + "..." + age); } // 建構區塊

    public void setName(String name) { this.name = name; }
    public void speak() { System.out.println(name + "..." + age); }
    public static void showCountry() { System.out.println("country=" + country); }
}

class StaticDemo {
    static { System.out.println("StaticDemo 靜態區塊1"); }
    public static void main(String[] args) {
        Person p = new Person("zhangsan", 100);
        p.setName("lisi");
        p.speak();
        Person.showCountry();
    }
    static { System.out.println("StaticDemo 靜態區塊2"); }
}

輸出順序:

StaticDemo 靜態區塊1
StaticDemo 靜態區塊2
靜態區塊
null...0          // 建構區塊(實例變數尚未顯式初始化)
lisi...100        // speak()
country=cn        // showCountry()

總結

  1. 類載入 ≠ 類初始化;載入只讀位元碼,初始化才執行靜態區塊。
  2. 靜態成員駐留方法區,實例成員駐留堆。
  3. 建構區塊會被編譯器複製到每個建構子開頭,早於建構子本體執行。
  4. 掌握 9 步實例化流程,有助於理解 final 欄位初始化、序列化、反射等進階主題。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved