static 表示「屬於類、不屬於實例」。JVM 在類加載階段為靜態成員分配內存、執行初始化,所有實例共享同一份拷貝。
public class Counter {
static int count = 0; // 類加載時初始化為 0
public Counter() { count++; }
}
Counter c1 = new Counter();
Counter c2 = new Counter();
System.out.println(Counter.count); // 2
System.out.println(c1.count); // 2 (不推薦對象訪問)
對比實例變量:每 new 一次分配一次內存,互不干擾。
ClassName.method() 調用this/superabstract 修飾(必須有實現)public class Utils {
public static int max(int a, int b) { return a > b ? a : b; }
}
Utils.max(3,5); // 5
類加載時按順序執行一次,用於複雜靜態初始化(載入驅動、初始化單例、解析配置)。
public class DB {
static {
try { Class.forName("com.mysql.jdbc.Driver"); }
catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); }
}
}
不持有外部類引用,可獨立實例化,常用於單例模式(Holder 模式)。
public class Singleton {
private Singleton() {}
private static class Holder { static final Singleton INSTANCE = new Singleton(); }
public static Singleton getInstance() { return Holder.INSTANCE; }
}
// 驗證代碼
class Parent { static { System.out.println("P-static"); } { System.out.println("P-instance"); } Parent() { System.out.println("P-ctor"); } }
class Child extends Parent { static { System.out.println("C-static"); } { System.out.println("C-instance"); } Child() { System.out.println("C-ctor"); } }
new Child();
/* 輸出:
P-static
C-static
P-instance
P-ctor
C-instance
C-ctor
*/
| 修飾目標 | 含義 | 訪問方式 |
|---|---|---|
| 基本型別變量 | 編譯期常量,進入常量池,調用處直接內聯 | ClassName.CONST |
| 引用型別變量 | 引用不可變,但對象內部狀態可變 | ClassName.LIST.add("x") 合法 |
| 方法 | 不可覆蓋、可類名調用 | ClassName.method() |
public class ConstDemo {
static final int MAX = 100;
static final List<String> LIST = new ArrayList<>(); // 引用不可變
static { LIST.add("init"); }
public static void main(String[] args) {
// MAX = 200; // 編譯錯誤
LIST.add("runtime"); // 合法!對象內容可變
System.out.println(LIST); // [init, runtime]
}
}
private static:類內部工具、單例構建器protected static:子類可見、包內可見public static:全局工具方法、常量、單例入口| 誤區 | 後果 | 正確做法 |
|---|---|---|
| 靜態方法中調用非靜態方法 | 編譯錯誤 | 傳入實例引用或改為實例方法 |
| 靜態集合作為緩存無清理策略 | 記憶體洩漏、OOM | 用 Caffeine/Guava Cache 或定時清理 |
| 多線程並發修改靜態變量 | 競態條件、數據不一致 | AtomicLong/ConcurrentHashMap/synchronized |
| 濫用 static 導致難測試 | 單元測試無法 Mock、狀態殘留 | 依賴注入替代靜態調用,或用 PowerMock |