在 Java 中,使用 final 修飾類表示該類不可被繼承。這是一項重要的設計決策,通常基於安全性、不可變性或性能考量。本文深入解析 final 類的語義、限制、最佳實踐及常見誤區。
extends FinalClass 的代碼將導致編譯錯誤:Cannot extend final class。final 類中的所有方法自動成為 final,不可被重寫(但字段不自動成為 final)。final 類仍可正常創建對象,區別於 abstract 類。// final 類定義
public final class Dinosaur {
int i = 7;
int j = 1;
SmallBrain x = new SmallBrain();
void f() { }
}
// 錯誤:嘗試繼承 final 類
// class Further extends Dinosaur {} // Compile Error: Cannot extend final class 'Dinosaur'
// 正常使用
public class Jurassic {
public static void main(String[] args) {
Dinosaur n = new Dinosaur();
n.f();
n.i = 40;
n.j++;
}
}
class SmallBrain { }
| 動機 | 說明 | 典型案例 |
|---|---|---|
| 安全性 | 防止惡意/意外子類破壞核心邏輯(如安全管理器、加密實現) | java.lang.String, java.lang.System, java.security.MessageDigest |
| 不可變性保證 | 確保類的不可變契約不被子類破壞 | Integer, LocalDate, 包裝類型 |
| 性能優化(歷史) | 早期 JVM 可將 final 方法內聯;現代 JIT 已自動優化,動機減弱 | 早期 JDK 版本 |
| API 穩定性 | 庫作者明確聲明:此類不擴展,僅組合使用 | 工具類、DTO、記錄類 |
final 類的字段仍可為非 final,對象狀態可變。private final 字段、無 setter、防御性拷貝。final class Impl implements Interface 完全合法。| 修飾目標 | 效果 | 典型用途 |
|---|---|---|
final class | 不可被繼承 | String、包裝類、工具類 |
final method | 不可被重寫 | 模板方法模式中的固定步驟 |
final field | 引用不可變(對象內容仍可變) | 常量、依賴注入字段、不可變對象狀態 |
若需測試 final 類:
mockito-inline 直接 Mock final 類/方法。final 類是 Java 設計者手中的「終極封印」,用於明確宣告:此類不擴展,僅組合。正確使用能提升 API 清晰度與安全性;濫用則會扼殺擴展性。決策原則:默認非 final,有確切理由時再加封。