| 修飾對象 | 語義 | 典型用途 |
|---|---|---|
| 類 | 不可繼承 | 工具類、不可變類、安全敏感類 |
| 方法 | 不可重寫 | 模板方法固定步驟、性能關鍵路徑、API 穩定性 |
| 字段 | 引用不可變(對象內容可變) | 常量、依賴注入字段、線程安全發布 |
| 局部變量/參數 | 值/引用不可變 | Lambda/匿名類捕獲、防禦性編程 |
public class OrderService {
// 編譯期常量:public static final + 基本類型/String → 常量池內聯
public static final int MAX_ITEMS = 100;
public static final String CURRENCY = "CNY";
// 運行期常量:構造器注入,引用不可變
private final PaymentGateway paymentGateway;
private final List listeners = new ArrayList<>(); // 集合引用固定,內容可變
public OrderService(PaymentGateway pg) {
this.paymentGateway = Objects.requireNonNull(pg); // 必須初始化
}
public void addListener(OrderListener l) {
listeners.add(l); // ✅ 修改集合內容合法
// listeners = new ArrayList<>(); // ❌ 編譯錯誤:改變引用
}
}
public abstract class DataExporter {
// 核心流程不可變
public final void export(DataSource source, OutputStream out) {
Header header = readHeader(source); // 1. 讀取頭部
List records = readRecords(source); // 2. 讀取數據
writeHeader(out, header); // 3. 寫入頭部
writeRecords(out, records); // 4. 寫入記錄
writeFooter(out); // 5. 寫入尾部
}
// 子類可定制的擴展點
protected abstract Header readHeader(DataSource source);
protected abstract List readRecords(DataSource source);
protected void writeHeader(OutputStream out, Header h) { /* 默認實現 */ }
protected abstract void writeRecords(OutputStream out, List records);
protected void writeFooter(OutputStream out) { /* 默認實現 */ }
}
// 不可變類標準範式
public final class ImmutablePoint {
private final int x, y;
public ImmutablePoint(int x, int y) { this.x = x; this.y = y; }
public int getX() { return x; }
public int getY() { return y; }
// 防禦性拷貝(若字段可變)
// 無 setter、無可變方法、類 final → 線程安全、可作 Map Key
}
// 安全敏感類禁止繼承
public final class SecurityManager {
private SecurityManager() {} // 單例/工廠
public static void checkPermission(Permission p) { /* ... */ }
}
public void process(List items) {
String prefix = "ITEM: "; // Java 8+ 無需显式 final,但實際不可變
// String prefix = "ITEM: "; prefix = "NEW"; // ❌ 編譯錯誤:非 effectively final
items.forEach(item -> {
System.out.println(prefix + item); // 捕獲 prefix
});
// 老版本匿名類寫法(需顯式 final)
Runnable r = new Runnable() {
@Override public void run() {
System.out.println(prefix); // 捕獲 final 變量
}
};
}
public void updateUser(final User user, final String newName) {
// user = new User(); // ❌ 編譯錯誤
// newName = "x"; // ❌ 編譯錯誤
user.setName(newName); // ✅ 修改對象狀態合法
// 意圖明確:不會替換參數引用,僅操作對象
}
public class Config {
private final String url; // 聲明不賦值
private final int timeout;
public Config(String profile) {
if ("prod".equals(profile)) {
url = "https://api.prod.com"; timeout = 5000;
} else {
url = "https://api.dev.com"; timeout = 10000;
}
// 所有構造器路徑必須初始化
}
}
transient final 字段:反序列化時不會恢復值(保持默認值),需在 readObject 手動處理。static final 基本類型/String:屬於類常量,不序列化。static final int X = 10; 編譯期內聯到調用處。| 組合 | 合法性 | 說明 |
|---|---|---|
| final + abstract (類) | ❌ | 互斥:final 禁止繼承,abstract 必須繼承 |
| final + abstract (方法) | ❌ | 互斥:final 禁止重寫,abstract 必須重寫 |
| final + static (方法) | ✅ | 類方法不可被隱藏(子類同簽名方法為隱藏非重寫) |
| final + synchronized | ✅ | 無衝突,final 限制繼承,synchronized 限制併發 |
static final 常量:UPPER_SNAKE_CASE(MAX_CONNECTIONS)lowerCamelCase(paymentGateway)lowerCamelCasefinal 是 Java 中表達「不可變意圖」的核心關鍵字。善用 final:
原則:默認加 final,除非必須修改。這不是強迫症,是防禦性編程的基本素養。