存取修飾符是 Java 封裝機制的基石,決定類別、欄位、方法、建構子對外部的可見性。本文系統整理四大修飾符規則、類別層級限制、繼承與跨包可見性矩陣、實戰案例與設計原則。
public | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| protected | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
| default (無) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| private | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
> **關鍵口訣**:public 都能訪,**protected 多一個「子類」**;**default 只有「同包」**;**private 只有「自己」**。
public 或 default,**不能**用 private/protected。public 類別,檔名必須與該類別同名。// package com.myapp.order;
class OrderValidator { // default 類別,外部模組不可見
boolean validate(Order o) { // default 方法
return o.getAmount() > 0;
}
}
public class OrderService { // public API
private final OrderValidator validator = new OrderValidator();
public void placeOrder(Order o) {
if (!validator.validate(o)) throw new IllegalArgumentException();
// ...
}
}
**優勢**:隱藏實作細節,測試時同包可直接驗證 OrderValidator,外部模組編譯期即報錯。
public abstract class AbstractExporter {
public final void export(Data data) { // final 禁止覆寫流程
beforeExport();
doExport(data); // protected 抽象方法,強制子類實作
afterExport();
}
protected void beforeExport() {} // protected 鉤子,子類可選覆寫
protected void afterExport() {}
protected abstract void doExport(Data data); // 核心擴充點
}
public class PdfExporter extends AbstractExporter {
@Override protected void doExport(Data data) { /* PDF 邏輯 */ }
@Override protected void beforeExport() { /* 初始化字體 */ }
}
**關鍵**:protected 讓子類**跨包**也能存取,同時對外部不可見,完美支援框架擴充。
public final class ImmutablePeriod {
private final LocalDate start; // private + final
private final LocalDate end;
public ImmutablePeriod(LocalDate start, LocalDate end) {
// 防禦性複製:防止呼叫端持有引用竄改
this.start = Objects.requireNonNull(start);
this.end = Objects.requireNonNull(end);
if (this.start.isAfter(this.end)) throw new IllegalArgumentException();
}
public LocalDate getStart() { return start; } // 回傳不可變物件安全
public LocalDate getEnd() { return end; }
// 刻意不提供 setter,保證不可變性
}
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {} // 私有建構子,禁止外部 new
public static Singleton getInstance() { return INSTANCE; }
}
protected = 同包 + 子類 = default + 子類 | **錯**!protected 允許**子類實例**存取 **其他子類實例** 的 protected 成員;default 不行。 |
| 介面方法預設 public,不可改 | **Java 9+** 介面支援 private 方法 (內部複用)、**static** 方法、**default** 方法。 |
| 內部類別 private 只能外部類存取 | **對**,但外部類**所有**內部類 (含巢狀) 皆可存取該私有內部類。 |
| final 類別不可繼承,但可繼承其方法 | **錯**!final 類別完全禁止繼承,方法自然也不可覆寫。 |
public static final 命名全大寫底線,基本型別或不可變物件安全;可變物件 (陣列、集合) **嚴禁**公開。module-info.java exports/opens 進一步控制編譯期/執行期可見性。存取修飾符不是語法糖,而是**架構邊界的宣示**:
public = 契約 API,嚴謹設計、向相容演進。protected = 框架擴充點,文檔化預期行為。default = 模組內部實現,重構自由、編譯期保護。private = 類別不變量核心,唯一真理來源。內化這四層邊界,即能寫出「易維護、難誤用、可演進」的專業 Java 程式碼。