前言
訪問權限控制是 Java 封裝性的核心機制,合理使用權限修飾符能實現「高內聚、低耦合」的設計。本文系統梳理類級與成員級四種權限(public、protected、default、private)的可見性矩陣、繼承規則、模塊化影響(JPMS)及實戰原則。
一、兩個維度的權限控制
| 維度 | 可用修飾符 | 默認權限 | 說明 |
| 類 (頂級類) | public / (無修飾符) | 包私有 (package-private) | 只能兩種選擇,無 protected/private |
| 成員 (字段/方法/構造器/內部類) | public / protected / (無) / private | 包私有 (package-private) | 四種全選擇,精細控制 |
二、四種權限可見性矩陣(核心必背)

| 修飾符 | 同一類 | 同包其他類 | 不同包子類 | 不同包非子類 | 口訣 |
| public | ✅ | ✅ | ✅ | ✅ | 公共,全球可見 |
| protected | ✅ | ✅ | ✅ | ❌ | 保護,子類可見(跨包需繼承) |
| default (無) | ✅ | ✅ | ❌ | ❌ | 包私有,僅同包可見 |
| private | ✅ | ❌ | ❌ | ❌ | 私有,僅自己可見 |
關鍵細節
- protected 的跨包訪問:僅限子類通過繼承訪問,不能通過父類引用訪問。即
Child.childMethod() 可調用 super.protectedMethod(),但 Parent p = new Child(); p.protectedMethod() 編譯報錯
- 構造器權限:決定類能否被實例化/繼承。
private 構造器 → 單例模式/工具類;protected 構造器 → 僅允許子類/同包實例化
- 接口成員:隱式
public static final (字段) / public abstract (方法),Java 8+ 允許 default/private/static 方法
三、類級權限:public vs package-private
| 權限 | 可見範圍 | 適用場景 | 文件命名規則 |
| public | 整個應用/模塊 | API 入口、實體類、異常、工具類 | 文件名 = 類名.java |
| default | 同一包內 | 內部實現類、輔助類、包級單例 | 無特殊要求,但建議同名 |
設計原則:盡量少用 public 類。只有真正需要對外暴露的 API 類才設為 public,內部實現類全部 package-private,減少模塊耦合,便於重構。
四、繼承與覆寫的權限規則
| 規則 | 說明 | 代碼示例 |
| 覆寫方法權限 ≥ 被覆寫方法權限 | 不能降低可見性,可提高 | 父 protected → 子 public ✅ / 父 public → 子 protected ❌ |
| private 方法不可覆寫 | 子類不可見,屬於類私有 | 子類定義同名方法屬於新方法,非覆寫 |
| default 方法跨包不可覆寫 | 不同包子類不可見 | 同包子類可覆寫為 public/protected/default |
| 構造器不可繼承/覆寫 | 子類通過 super() 調用父構造器 | 父構造器 private → 子類無法實例化(除非同包) |
五、JPMS (Java 9+ 模塊系統) 的新增影響
模塊系統在類權限之上增加模塊導出層級:
module com.myapp.core {
// 僅導出 api 包,impl 包內部類對外不可見(即使 public)
exports com.myapp.core.api;
// 不導出 com.myapp.core.impl
}
| 類修飾符 | 模塊導出 | 最終可見性 |
| public | exports | 全局可見 |
| public | 不導出 | 僅模塊內可見(強封裝) |
| default | 無關 | 僅同包可見 |
這意味著:public 類不再等於全局可見,需配合 module-info.java 導出才能跨模塊訪問。
六、實戰最佳實踐原則
- 原則 1:最小權限原則
- 默認 private,需要時再放寬
- 字段 永遠 private,提供 public/protected getter/setter
- 內部輔助方法 private
- 原則 2:面向接口編程
- 對外暴露
public interface,實現類 package-private 或 public 但不導出
- 依賴倒置:高層模塊依賴抽象,不依賴具體實現類
- 原則 3:繼承設計謹慎用 protected
- 只有明確設計為「供子類擴展」的方法/字段才用 protected
- 優先組合/委託替代繼承,減少 protected 暴露
- 文檔註釋 @apiNote 說明 protected 成員的擴展契約
- 原則 4:構造器權限控制實例化
- 工具類/單例:
private Constructor()
- 抽象基類/僅供框架實例化:
protected Constructor()
- Builder 模式:構造器 private,靜態工廠方法 public
- 原則 5:模塊化時代的封裝升級
- 內部實現包 不導出,即使類是 public 也無法被外部模塊訪問
- 使用
opens ... to 精確開放反射訪問權限(如 Spring/MyBatis 需要)
七、常見面試題陷阱
| 題目 | 陷阱 | 正確答案 |
| protected 能被同包類訪問嗎? | 以為只有子類 | ✅ 能,同包無需繼承即可訪問 |
| 子類能覆寫父類 default 方法嗎? | 忽略包關係 | 同包 ✅,不同包 ❌(不可見) |
| interface 中定義的變量默認修飾符? | 以為是 default | public static final(隱式) |
| 為什麼外部類不能用 private/protected? | 不理解類級權限只有兩種 | 類級只有 public/default,無意義 |
| 模塊系統下 public 類一定可見嗎? | 忽略 module-info.java | 不導出則不可見(強封裝) |
八、總結
- 四大權限:
public > protected > default > private,可見性遞減
- 類級只有 public/default;成員級四種全有
- protected 跨包僅限「繼承訪問」,非引用訪問
- 覆寫方法權限不能降低,構造器不可繼承
- Java 9+ 模塊系統增加導出層級,public 不再等於全局可見
- 實戰堅持:字段私有、最小權限、面向接口、模塊強封裝
- 上一篇文章: JSP/Servlet 工作原理深度解析:生命周期、請求處理流程與 MVC 架構定位
- 下一篇文章: Java 發展史與白皮書解讀:從 Oak 到 Java 17+ 的技術演進全景
Copyright ©
程式碼之家 All Rights Reserved