java中final關(guān)鍵字的各種用法和注意事項詳解
一、final 修飾變量
當一個變量被聲明為 final 時,它只能被賦值一次。一旦被初始化,其值就不能再被改變。這類似于其他語言中的“常量”概念。
根據(jù)變量類型的不同,其“不可變”的含義略有差異:
1. final 基本類型變量
值本身不可變。
final int maxRetries = 5; // maxRetries = 10; // 編譯錯誤!不能再次賦值
2. final 引用類型變量
引用本身不可變,但其所指向的對象內(nèi)部的狀態(tài)是可以改變的(除非對象本身也是不可變對象,如 String)。
final StringBuilder sb = new StringBuilder("Hello");
sb.append(" World"); // ?? 允許:修改對象內(nèi)部狀態(tài)
// sb = new StringBuilder(); // ? 編譯錯誤!不能改變引用指向另一個對象
初始化時機:
final 變量必須在聲明時或構(gòu)造函數(shù)結(jié)束前被初始化。
- final 實例變量:必須在聲明時、實例初始化塊中或每個構(gòu)造函數(shù)結(jié)束前被初始化。
- final 靜態(tài)變量(常量):必須在聲明時、靜態(tài)初始化塊中被初始化。
class Example {
final int instanceVar; // 必須在構(gòu)造函數(shù)中初始化
static final String CONSTANT = "Value"; // 聲明時初始化
public Example(int value) {
this.instanceVar = value; // 初始化
}
}
二、final 修飾方法
當一個方法被聲明為 final 時,意味著該方法不能被子類重寫(Override)。
使用場景:
- 防止繼承改變核心邏輯:確保父類中的某個方法行為在子類中保持不變,防止其被意外修改,保證程序的安全性、一致性和正確性。
- 效率考慮(歷史原因):早期 Java 版本中,final 方法在編譯時可能會被內(nèi)聯(lián)(Inline),帶來微小的性能提升。但現(xiàn)代 JVM 非常智能,會自動完成優(yōu)化,這個理由如今已不那么重要。
class Parent {
// 此方法不能被子類重寫
public final void criticalBusinessLogic() {
// ... 核心算法
}
}
class Child extends Parent {
// ? 編譯錯誤!Cannot override the final method
// @Override
// public void criticalBusinessLogic() { ... }
}三、final 修飾類
當一個類被聲明為 final 時,意味著這個類不能被繼承,即不能有子類。
使用場景:
- 設(shè)計上的“終結(jié)”:表示這個類在設(shè)計上已經(jīng)非常完善,不需要也不應(yīng)該被擴展,例如
String、Integer等包裝類。這保證了該類行為的絕對穩(wěn)定和安全。 - 安全:防止惡意代碼通過創(chuàng)建子類來破壞核心功能(例如通過重寫方法)。
- 不可變類:創(chuàng)建不可變類(Immutable Class)時,類本身通常被聲明為
final,以防止子類化破壞其不可變性。
final class ImmutableClass {
private final int value;
public ImmutableClass(int value) {
this.value = value;
}
// 只有g(shù)etter,沒有setter
public int getValue() {
return value;
}
}
// ? 編譯錯誤!Cannot inherit from final class
// class SubClass extends ImmutableClass { ... }
四、final 修飾參數(shù)
方法參數(shù)也可以被聲明為 final。這表示該參數(shù)在方法體內(nèi)不能被重新賦值。
使用場景與優(yōu)點:
- 代碼清晰與安全:明確表示這個參數(shù)的值在方法內(nèi)不會被改變,提高了代碼的可讀性和可維護性。
- 用于匿名內(nèi)部類:在 Java 8 之前,如果匿名內(nèi)部類需要訪問一個局部變量,該變量必須被聲明為
final。Java 8 引入了“有效最終(effectively final)”的概念(即變量雖然沒有明確聲明為 final,但自初始化后從未被修改),使得語法上不再強制要求final關(guān)鍵字,但其語義仍然是不可變的。
// Java 8 之前:必須加 final
public void oldMethod() {
final int oldVar = 10;
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(oldVar); // 需要訪問外部局部變量
}
}).start();
}
// Java 8 及之后:effectively final 即可
public void newMethod() {
int newVar = 10; // 沒有 final,但從未被修改,所以是 effectively final
new Thread(() -> System.out.println(newVar)).start(); // 可以訪問
// newVar = 20; // 如果加上這行,newVar 就不再是 effectively final,上面的lambda表達式會報錯
}
建議:即使在新版本中,為了代碼清晰和防止意外修改,很多編碼規(guī)范依然建議將不會被修改的參數(shù)顯式地聲明為 final。
五、重要注意事項總結(jié)
- 空白 final(Blank Final):聲明時未初始化的 final 變量稱為“空白 final”。必須在構(gòu)造函數(shù)中完成初始化,編譯器會嚴格檢查這一點。
- final 與靜態(tài)(static):
static final組合用于定義類級別的全局常量,命名規(guī)范通常使用全大寫字母和下劃線(如MAX_VALUE)。 - final 與并發(fā):final 變量的初始化安全由 JMM(Java內(nèi)存模型)保證。一個正確構(gòu)造的對象的 final 字段,在任何線程中看到時,都已經(jīng)是初始化完成的值。這使得在不使用同步的情況下,也能安全地發(fā)布不可變對象。
- 性能:現(xiàn)代 JVM 對 final 的優(yōu)化已經(jīng)非常成熟,不必過分追求使用 final 來提升性能。應(yīng)更多地將其用于設(shè)計目的,如保證不可變性和安全性。
- 集合與 final:
final List<String> myList = new ArrayList<>();只表示引用myList不能指向另一個 ArrayList,但仍然可以調(diào)用myList.add("item")來修改列表內(nèi)容。如果要一個完全不可變的集合,應(yīng)使用Collections.unmodifiableList()或 Java 9+ 的List.of()等方法。
總結(jié)表
| 修飾目標 | 含義 | 關(guān)鍵點 |
|---|---|---|
| 變量(基本類型) | 值不可變 | 只能賦值一次 |
| 變量(引用類型) | 引用不可變 | 不能指向新對象,但對象內(nèi)部狀態(tài)可修改 |
| 方法 | 不能被子類重寫(Override) | 用于鎖定方法實現(xiàn),保證核心邏輯 |
| 類 | 不能被繼承 | 常用于工具類、不可變類或出于安全考慮的核心類(如 String) |
| 參數(shù) | 方法內(nèi)部不能對參數(shù)重新賦值 | 提高代碼可讀性,是匿名內(nèi)部類/λ表達式訪問外部變量的基礎(chǔ)(Java 8+ 為 effectively final) |
希望這個詳細的解釋能幫助你全面理解 Java 中的 final 關(guān)鍵字!
到此這篇關(guān)于java中final關(guān)鍵字的各種用法和注意事項的文章就介紹到這了,更多相關(guān)java final關(guān)鍵字用法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis-Plus:saveOrUpdate根據(jù)指定字段更新或插入方式
這篇文章主要介紹了MyBatis-Plus:saveOrUpdate根據(jù)指定字段更新或插入方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
idea報錯Since Maven 3.8.1 http repositorie
Maven 3.8.1禁用HTTP倉庫,導(dǎo)致IDEA構(gòu)建項目報錯,解決方案包括降級Maven至3.6.3或更新依賴包版本至支持HTTPS2025-08-08
java 學(xué)習(xí)筆記(入門篇)_java的安裝與配置
學(xué)習(xí)Java已經(jīng)很長時間了,由于基礎(chǔ)不好遇到問題就無從下手,所以,打算寫Java的隨手筆記來鞏固基礎(chǔ),加強學(xué)習(xí),接下來講解java的安裝,配置等,感興趣的朋友可以參考下2013-01-01
SpringBoot查詢數(shù)據(jù)庫導(dǎo)出報表文件方式
這篇文章主要介紹了SpringBoot查詢數(shù)據(jù)庫導(dǎo)出報表文件方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-04-04

