訪問控制是封裝的核心,決定了類的內部結構對外部的可見性。本文通過權限矩陣、代碼實驗、設計原理解析,全方位講透 Java 四大修飾符。
| 修飾符 | 同一類內 | 同一包下 | 子類(異包) | 其他包 | 核心用途 |
|---|---|---|---|---|---|
| public | ✓ | ✓ | ✓ | ✓ | 對外公開 API |
| protected | ✓ | ✓ | ✓ | ✗ | 繼承體系共享 |
| default (無) | ✓ | ✓ | ✗ | ✗ | 包級內聚 |
| private | ✓ | ✗ | ✗ | ✗ | 內部實現隱藏 |
原則:訪問權限越小,封裝性越強,系統越穩定。
com.demo.test1
├── Person.java // 基類
├── Student.java // 同包類
└── Teacher.java // 子類
com.demo.test2
└── Parents.java // 異包無關類
// Person.java
public class Person {
public String uname = "王五";
public void introduceMyself() { System.out.println(uname); }
}
// Student.java (同包)
public class Student {
Person p = new Person();
public void test() { System.out.println(p.uname); } // ✓ 可訪問
}
// Teacher.java (子類)
public class Teacher extends Person {
public void test1() { System.out.println(new Person().uname); } // ✓ 可訪問
}
// Parents.java (異包)
public class Parents {
Person p = new Person();
public void test2() { System.out.println(p.uname); } // ✓ 可訪問
}
結果:四個位置全部訪問成功。
將 uname 改為 protected:
// Person.java
protected String uname = "王五";
結果:Parents 編譯報錯 The field Person.uname is not visible,其餘三處正常。
結論:protected 允許同包 + 子類(含異包子類),禁止無關異包類。
將 uname 改為 private:
// Person.java
private String uname = "王五";
// 必須提供 getter/setter
public String getUname() { return uname; }
public void setUname(String uname) { this.uname = uname; }
結果:只有 Person 內部可直接訪問,外部必須通過 getter/setter。
去掉修飾符:
// Person.java
String uname = "王五"; // default
結果:Student 可訪問,Teacher(異包子類)和 Parents 均報錯不可見。
結論:default 僅限同包可見,甚至繼承關系跨包也不可見。
| 誤區 | 正確認知 |
|---|---|
| 字段設為 public 方便訪問 | 破壞封裝,改用 private + getter/setter |
| protected 僅用於繼承 | 同包類也可訪問,不限於子類 |
| default 是「預設公開」 | default 是「包私有」,比 protected 更嚴格 |
| 接口方法可聲明 protected | 接口方法隱式 public,不可加其他修飾符 |
super())掌握訪問修飾符,就是掌握了「什麼該藏、什麼該露、給誰看」的架構設計權力。