核心含義
static 表示**「屬於類別本身,而非屬於某個實例」**。靜態成員在類別載入時初始化,生命週期 = 類別生命週期 (通常 = 應用程式生命週期)。
四大用法
1. 靜態變數 (類別變數)
public class User {
private static int userCount = 0; // 所有實例共享
private String name;
public User(String name) {
this.name = name;
userCount++; // 透過類別名存取更清晰:User.userCount++
}
public static int getUserCount() { return userCount; }
}
- 記憶體:方法區 (Metaspace, Java 8+) / 永久代 (Java 7-),**單一份複本**。
- 存取:
ClassName.staticField (推薦) 或 instance.staticField (不推薦,誤導為實例成員)。
- 初始化順序:靜態變數按宣告順序 → 靜態初始化區塊按順序 → 實例變數/區塊 → 建構子。
2. 靜態方法 (類別方法)
public class MathUtils {
public static int add(int a, int b) { return a + b; }
// 無法存取 this、super、非靜態成員
}
- 無
this 參數,不可為 abstract (介面 default/static 方法除外)。
- 不可覆寫 (override),子類別同名靜態方法為**隱藏 (hiding)**,非多型。
- 適用:工具方法、工廠方法、單例存取點、無狀態邏輯。
3. 靜態初始化區塊
public class Config {
static final String DB_URL;
static {
// 複雜初始化邏輯:讀取檔案、建立連線池、載入原生庫
try { DB_URL = loadFromFile(); }
catch (IOException e) { throw new ExceptionInInitializerError(e); }
}
}
- 類別載入時**自動執行一次**,按宣告順序。
- 異常會包裝為
ExceptionInInitializerError,導致類別不可用。
- 常用於:載入 Native Library (
System.loadLibrary)、初始化昂貴靜態資源。
4. 靜態內部類 (巢狀類別)
public class Outer {
private static String config = "CFG";
private String instanceData = "INST";
static class StaticNested {
void print() {
System.out.println(config); // 僅能存取外部類 static 成員
// System.out.println(instanceData); // 編譯錯誤
}
}
class Inner { // 非靜態內部類
void print() {
System.out.println(config);
System.out.println(instanceData); // 可存取外部實例成員
}
}
}
| 特性 | 靜態內部類 | 非靜態內部類 |
| 建立實例 | new Outer.StaticNested() (無需外部實例) | outer.new Inner() (需外部實例) |
| 存取外部成員 | 僅 static | 所有 (含私有) |
| 隱含引用 | 無 | 持有 Outer.this |
| 序列化 | 獨立 | 連帶序列化外部實例 |
單例模式首選靜態內部類** (見 113970)。
static 導入
import static java.lang.Math.PI;
import static java.lang.System.out;
import static com.utils.StringUtils.*;
public class Demo {
public static void main(String[] args) {
out.println(PI); // 直接用 PI、out、isBlank()
}
}
- 簡化常數/靜態方法呼叫,濫用會降低可讀性 (來源不明)。
- 僅導入**常用常數/工具方法**,避免導入大量方法污染命名空間。
靜態成員限制總覽
| 限制 | 說明 |
| 不可存取 this / super | 無實例關聯 |
| 不可直接呼叫非靜態方法/存取非靜態欄位 | 需實例引用 |
| 不可為 abstract (Java 8 前) | 介面可有 static/default 方法 |
| 不可覆寫 (override) | 子類別同名為隱藏 |
| 靜態變數宣告時建議顯式初始化 | 未初始化有預設值 (0/null/false),但易誤解 |
常見陷阱與最佳實踐
- 多執行緒競態:靜態可變狀態需同步 (
synchronized, AtomicInteger, ConcurrentHashMap) 或用 ThreadLocal 隔離。
- 類別載入死鎖:靜態區塊中觸發其他類別載入,雙方互等鎖 → 死鎖。避免靜態區塊做複雜邏輯/鎖/網路呼叫。
- 記憶體洩漏:靜態集合持有大量物件不釋放 → GC 無法回收。用弱引用、定期清理、或生命週期管理器。
- 單元測試困難:靜態方法難以 Mock (需 PowerMock/Mockito-inline)。核心邏輯改用實例方法 + 依賴注入。
- 序列化:
static 欄位**不參與序列化** (屬於類別非實例)。
- 常數定義:
static final 基本型別/字串 → 編譯期常數內聯 (呼叫端嵌入值),修改需重編譯所有呼叫端。非常數用 static final 物件或 static getter。
現代 Java 新特性
- 介面 static 方法 (Java 8):工具方法可放介面,如
Stream.of(), Comparator.naturalOrder()。
- 靜態巢狀類別模式匹配 (Java 17+):
if (obj instanceof Outer.StaticNested n) ...。
- 上一篇文章: Java 匿名內部類深度解析:語法、捕獲變數、初始化、final 限制原因
- 下一篇文章: Java 實現多重繼承:介面與內部類兩大核心方案
Copyright ©
程式碼之家 All Rights Reserved