靜態成員四大核心特征
- 全局唯一:屬於類,不屬於實例。所有實例共享同一份副本,任一處修改全局可見。
- 優先加載,僅加載一次:類加載階段(準備/初始化)分配內存、賦值,早於任何實例創建。
- 調用無需實例:
ClassName.staticField、ClassName.staticMethod(),雖實例也能訪問但不推薦。
- 生命周期 = 類生命周期:從類加載到類卸載(ClassLoader 回收),遠長於實例生命周期。
靜態 vs 非靜態 訪問規則
| 訪問者 \ 被訪問 | 靜態字段/方法 | 非靜態字段/方法 |
| 靜態方法 | ✅ 直接訪問 | ❌ 編譯錯誤(無 this) |
| 非靜態方法 | ✅ 直接訪問 | ✅ 通過 this 訪問 |
口訣:靜態只能訪問靜態;非靜態可訪問靜態與非靜態。
靜態初始化塊 vs 實例初始化塊
public class Demo {
static { System.out.println("靜態塊:類加載時執行,僅一次"); }
{ System.out.println("實例塊:每 new 一次執行,構造器前"); }
public Demo() { System.out.println("構造器"); }
}
// 輸出順序:
// 靜態塊
// 實例塊
// 構造器
// 實例塊
// 構造器
靜態內部類 vs 非靜態內部類
| 維度 | 靜態內部類 (static class Inner) | 非靜態內部類 (class Inner) |
| 外部類引用 | 不持有 | 隱式持有 Outer.this |
| 創建方式 | new Outer.Inner() | new Outer().new Inner() |
| 訪問外部成員 | 僅靜態成員 | 靜態 + 非靜態均可 |
| 序列化風險 | 無 | 序列化會連帶外部類實例 |
| 典型用途 | 工具類、Builder 模式、單例持有者 | 需要外部狀態的迭代器、事件監聽器 |
代碼示範
class Outer {
private static String staticMsg = "Static";
private String instanceMsg = "Instance";
static class StaticNested {
void print() { System.out.println(staticMsg); /* instanceMsg 不可見 */ }
}
class Inner {
void print() { System.out.println(staticMsg + " | " + instanceMsg); }
}
}
public class Test {
public static void main(String[] args) {
Outer.StaticNested sn = new Outer.StaticNested();
sn.print();
Outer outer = new Outer();
Outer.Inner in = outer.new Inner();
in.print();
}
}
常見面試陷阱
- 靜態方法能否被覆寫?不能。子類同名靜態方法叫「隱藏」,調用由編譯期類型決定,非多態。
- 介面中能否有 static 方法?Java 8+ 支援
static default 方法,作為介面工具方法,不被實現類繼承。
- final static 基本類型 vs 引用類型:基本類型為編譯期常量(字節碼內聯),引用類型僅引用不可變,對象內容可變。