final 與 instanceof 是 Java 基礎語法中高頻使用但易混淆細節的兩大關鍵字。本文系統梳理它們的作用範圍、語義規則、常見陷阱與最佳實踐。
| 修飾對象 | 語義 | 代碼示例 | 關鍵規則 |
|---|---|---|---|
| 類別 | 不可被繼承 | final class Immutable {} | 隱含所有方法隱性 final;String、Integer 等不可變類典型應用 |
| 方法 | 不可被重寫 | public final void init() {} | private 方法隱性 final;構造器不可被繼承故無 final |
| 變量 | 引用/值不可變更 | 見下文詳細分類 | 編譯期常量折疊優化;空白 final 須在構造器初始化 |
public class FinalVariableDemo {
// 1. 實例/靜態常量:編譯期確定,命名全大寫+下劃線
static final double PI = 3.1415926;
final String INSTANCE_CONST = "FIXED";
// 2. 空白 final:聲明時不賦值,構造器/初始化塊必須賦值
final String blankFinal;
{ blankFinal = "init block"; } // 或構造器賦值
// 3. 方法參數:防止方法內部修改參數引用
public void process(final List list, final int threshold) {
// list = new ArrayList<>(); // ❌ 編譯錯誤:不可修改引用
list.add("allowed"); // ✅ 允許:修改對象內部狀態
// threshold = 100; // ❌ 編譯錯誤:基本類型值不可變
}
// 4. 局部變量:匿名內部類/Lambda 捕獲必須 final 或 effectively final
public Runnable createTask(final String msg) {
return () -> System.out.println(msg); // Java 8+ effectively final 自動推斷
}
}
final List list = new ArrayList<>();
list.add("A"); // ✅ 合法:修改對象內容
// list = new LinkedList<>(); // ❌ 非法:修改引用指向
final int[] arr = {1, 2, 3};
arr[0] = 99; // ✅ 合法:修改陣列元素
// arr = new int[5]; // ❌ 非法:修改引用
記住: final 守護的是「引用地址不變」,而非「對象狀態不變」。真正不可變需結合不可變集合、防御性拷貝、final 域鏈。
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
public class InstanceofDemo {
public static void main(String[] args) {
Animal a = new Animal();
Dog d = new Dog();
Animal ad = new Dog(); // 多態:父類引用指向子類對象
System.out.println(a instanceof Animal); // true
System.out.println(a instanceof Dog); // false
System.out.println(d instanceof Animal); // true (子類是父類實例)
System.out.println(d instanceof Dog); // true
System.out.println(ad instanceof Animal); // true
System.out.println(ad instanceof Dog); // true (關鍵:看實際對象類型!)
System.out.println(ad instanceof Cat); // false
// null 檢查
Dog nullDog = null;
System.out.println(nullDog instanceof Dog); // false (null 不是任何類型實例)
}
}
true 表示左邊對象是右邊類型或其子類型實例if (obj instanceof String s) { s.length(); } 自動轉型綁定變量
final Animal animal = new Dog();
// animal = new Cat(); // ❌ final 禁止修改引用
if (animal instanceof Dog) {
Dog dog = (Dog) animal; // 安全轉型
dog.bark();
}
// Java 16+ 模式匹配更簡潔
if (animal instanceof Dog dog) {
dog.bark(); // 直接使用 dog
}
| 代碼片段 | 結果 | 解析 |
|---|---|---|
final int i = 10; i = 20; | 編譯錯誤 | 基本類型 final 值不可變 |
final List l = new ArrayList(); l.add(1); | 運行正常 | 修改對象內容非修改引用 |
Object o = "test"; o instanceof String | true | 實際對象是 String |
null instanceof Object | false | null 無類型 |
int[] arr = new int[3]; arr instanceof Object | true | 數組是 Object 子類 |
List | true | 介面向上檢查 |
搞懂 final 守護「引用不變」、instanceof 檢查「類型關係」,Java 類型系統的基石就穩了。