修飾符適用性矩陣
| 修飾符 | 類 | 成員方法 | 構造方法 | 成員變量 | 局部變量 |
| abstract | Y | Y | - | - | - |
| static | - | Y | - | Y | - |
| public | Y | Y | Y | Y | - |
| protected | - | Y | Y | Y | - |
| private | - | Y | Y | Y | - |
| synchronized | - | Y | - | - | - |
| native | - | Y | - | - | - |
| transient | - | - | - | Y | - |
| volatile | - | - | - | Y | - |
| final | Y | Y | - | Y | Y |
註:頂層類只能用 public 或默認(package-private),不能用 private/protected。
一、訪問控制修飾符:封裝的四大層級
| 級別 | 關鍵字 | 同類 | 同包 | 子類(異包) | 非子類(異包) |
| 公開 | public | ✓ | ✓ | ✓ | ✓ |
| 受保護 | protected | ✓ | ✓ | ✓ | ✗ |
| 默認 | (無) | ✓ | ✓ | ✗ | ✗ |
| 私有 | private | ✓ | ✗ | ✗ | ✗ |
核心原則:盡可能降低可見度,只暴露必要 API,隱藏實現細節。
二、abstract 修飾符:契約與模板
- 抽象類:不可實例化,可包含抽象/非抽象方法、構造器(供子類調用)。
- 抽象方法:無方法體,強制子類實現(除非子類也是抽象類)。
- 禁忌:無抽象構造器、無抽象靜態方法、不能與
final 共存(語義衝突)。
三、final 修飾符:不可變性保證
1. final 類
- 不可被繼承(如
String、Integer)
- 適用場景:安全敏感、不可變對象、確信不再擴展
2. final 方法
- 不可被重寫
- 適用場景:模板方法固定算法骨架、安全敏感邏輯
3. final 變量(常量)
| 類型 | 初始化時機 | 內存區域 | 典型用法 |
| static final | 聲明時/靜態塊 | 方法區 | 編譯期常量、配置常量 |
| 實例 final | 聲明時/構造器/實例塊 | 堆 | 對象標識、不可變引用 |
| 局部 final | 首次賦值前 | 棧 | 方法內常量、匿名類捕獲變量 |
關鍵細節
- 引用類型 final:引用不可變,但對象內部狀態可變(
final List list = new ArrayList(); list.add(1); // 合法)
- 編譯期常量:
static final 基本類型/String + 編譯期可知值 → 編譯器內聯到調用處,修改需重編譯調用方。
- 構造器不能 final:構造器本身不可繼承,加 final 無意義。
四、static 修飾符:類級別狀態與行為
1. 靜態變量(類變量)
- 內存僅一份,屬於類不屬於實例
- 所有實例共享,可作跨實例通信媒介
- 生命周期:類加載 → 類卸載
2. 靜態方法
- 不能用 this/super:無實例上下文
- 不能直接訪問實例成員:需通過對象引用
- 可直接訪問靜態成員
- 不能是 abstract:必須有實現體(介面默認方法除外)
- 適用:工具方法、工廠方法、單例獲取
3. 靜態代碼塊
static {
// 類加載時執行,按聲明順序
// 用於複雜靜態初始化、註冊驅動、載入本地庫
}
- 僅執行一次,線程安全由類加載器保證
- 不能直接訪問實例成員
- 異常處理:拋出
ExceptionInInitializerError 導致類不可用
五、組合使用模式與最佳實踐
| 模式 | 組合 | 語義 | 典型例子 |
| 常量 | public static final | 全局可見、不可變、編譯期內聯 | Math.PI, Integer.MAX_VALUE |
| 單例 | private static final + 私有構造器 | 類級唯一實例、延遲/飽漢初始化 | Runtime.getRuntime() |
| 模板方法 | final 方法 + abstract 方法 | 固定骨架、延遲細節到子類 | AbstractList, HttpServlet |
| 不可變對象 | final 類 + final 域 + 無 setter | 線程安全、可自由共享 | String, LocalDate |
| 工具類 | final 類 + 私有構造器 + static 方法 | 防實例化、純靜態方法集合 | Collections, Arrays |
六、常見面試陷阱
abstract 與 final 互斥?是。抽象要求繼承實現,final 禁止繼承/重寫。
static 與 abstract 互斥?是。靜態屬於類,抽象要求子類實例實現。
private 方法可被重寫?不能。私有方法不可見,子類同名方法是新方法而非重寫。
final 引用指向的對象內容可變?可。final 只鎖定引用地址。
- 介面中變量默認修飾符?
public static final(常量)。方法默認 public abstract(Java 8 前)。
總結
修飾符是 Java 封裝、繼承、多態、線程安全的語法基石。熟練掌握 訪問控制四級權限、abstract/final/static 三大核心修飾符的語義邊界與組合模式,是寫出高內聚、低耦合、線程安全 Java 代碼的前提。建議將上表作為開發速查卡,代碼評審時重點檢查「是否過度暴露」、「final 是否缺失」、「static 是否濫用」。