static 是 Java 中「屬於類、不屬於實例」的核心修飾符。本文系統梳理靜態變數、靜態方法、靜態代碼塊、靜態內部類、static final 常量五大用法,剖析 JVM 類加載初始化時序、內存佈局、線程安全與常見誤區。
| 成員類型 | 語法 | 存儲位置 (Java 8+) | 初始化時機 | 訪問方式 |
|---|---|---|---|---|
| 靜態變數 | static int count; | Metaspace (類元資料) / Heap (對象頭指向) | 類準備階段賦零值 → 初始化階段賦指定值 | ClassName.count 或 obj.count (不推薦) |
| 靜態方法 | static void foo() | Metaspace (方法區) | 類加載完成即可用 | ClassName.foo() |
| 靜態代碼塊 | static { ... } | Metaspace (字節碼) | 類初始化階段,按聲明順序執行 | 無直接調用,JVM 自動執行 |
| 靜態內部類 | static class Inner {} | Metaspace (獨立類對象) | 首次主動使用時加載 (延遲載入) | Outer.Inner |
| static final 常量 | static final int MAX = 100; | 編譯期常量 → 字節碼常量池 / 運行時常量池 | 編譯期確定 (基本型別/String) → 類加載 | ClassName.MAX (編譯期內聯) |
public class StaticDemo {
static int a = 1; // 1. 準備階段 a=0 → 初始化階段 a=1
static int b; // 2. 準備階段 b=0
static { // 3. 靜態代碼塊 1
a = 10;
System.out.println("Block1 a=" + a); // 10
}
static int c = 20; // 4. 初始化 c=20
static { // 5. 靜態代碼塊 2
b = a + c; // b = 30
System.out.println("Block2 b=" + b); // 30
}
// 類加載完成,a=10, b=30, c=20
}
鐵律:靜態變數賦值與靜態代碼塊**按源碼順序**從上到下執行,static final 編譯期常量 (基本型別/String) 在準備階段直接賦值,不參與
this、superpublic class Singleton {
private Singleton() {}
private static class Holder {
static final Singleton INSTANCE = new Singleton(); // 類加載時初始化,線程安全
}
public static Singleton getInstance() { return Holder.INSTANCE; }
}
優勢:延遲載入 (首次調用 getInstance 才加載 Holder)、零鎖線程安全、防序列化/反射破壞需額外處理。
// A.java
public class A { public static final String VERSION = "1.0"; }
// B.java
public class B { public static void main(String[] args) { System.out.println(A.VERSION); } }
編譯 B.java 時,A.VERSION 常量值 "1.0" 會**內聯**到 B 的字節碼中。若後續修改 A.VERSION = "2.0" 並**僅重新編譯 A**,B 運行時仍輸出 1.0。
**解決**:修改常量值後**全量重新編譯**,或改用 static final 非基本型別 (如 new String("1.0")) 強制運行時解析。
| 題目 | 答案要點 |
|---|---|
| static 變數佔實例內存嗎? | 不佔,屬於類,僅一份拷貝 |
| static 方法能調用非 static 方法嗎? | 不能直接調用,需實例引用 |
| 靜態代碼塊 vs 建構代碼塊 執行順序? | 靜態代碼塊 (類加載一次) → 建構代碼塊 (每 new 一次) → 建構子 |
| 介面中可定義 static 方法嗎? | Java 8+ 可 (default/static 方法),Java 7 不可 |
| static final 修飾物件引用,物件內容可變嗎? | 引用不可變,物件內容可變 (如 static final List list = new ArrayList()) |
static 看似基礎,實則貫穿類加載、內存模型、線程安全、單例實現、常量傳播等核心機制。搞清「屬於類、按順序初始化、無 this、可內聯」五大特性,能讓你在架構設計、效能調優、疑難排查中游刃有餘。