final
final 是一個修飾符,是 Java 程式語言中的一個關鍵字,可以用來修飾變數、方法、以及類。使用 final
的效果是不同的,取決於它修飾的物件型別。下面我會分別解釋 final
修飾變數、方法和類時的效果。
final 修飾變數
當 final
修飾一個變數時,這個變數就變成了一個常量,也就是說它的值只能被賦值一次,一旦賦值之後就不能被修改了。如果嘗試修改 final
變數的值,編譯器會報錯。
final int number = 10; // 初始化 final 變數
// number = 15; // 編譯錯誤,不能修改 final 變數的值
final 修飾方法
當 final
修飾一個類的方法時,這個方法不能被子類覆蓋或重寫。這意味著子類不能提供一個具有相同名稱和引數型別的方法。
class Parent {
final void show() {
System.out.println("這是一個 final 方法。");
}
}
class Child extends Parent {
// 編譯錯誤,不能覆蓋 final 方法
// void show() {
// System.out.println("嘗試覆蓋 final 方法。");
// }
}
final 修飾類
當 final
修飾一個類時,表示這個類不能被繼承。換句話說,沒有其他類能夠繼承 final 類。
final class FinalClass {
// 類的定義
}
// 編譯錯誤,不能繼承 final 類
// class SubClass extends FinalClass {
// }
finalize
finalize()
方法在 Java 中是與物件生命週期關聯的一個概念。當一個物件不再有任何的引用指向它,也就是說,這個物件不再被程式中的其他部分所需要時,Java 虛擬機器(JVM)的垃圾收集器(GC)可能會考慮將其回收以釋放記憶體資源。在垃圾收集器決定回收物件之前,finalize()
方法會被呼叫,給予了這個物件一個機會來進行清理工作,比如關閉開啟的資源等。
然而,finalize()
方法存在幾個問題:
- 不確定性:
finalize()
方法被呼叫的具體時間是不確定的。垃圾收集器執行的時間取決於多種因素,包括 JVM 的記憶體使用情況、垃圾收集演算法等。這意味著,從物件不再有引用到finalize()
方法被呼叫之間的時間可能非常長,甚至可能永遠不會被呼叫。 - 效能問題:由於
finalize()
執行不確定,且可能影響垃圾收集的效率,過度依賴finalize()
方法可能會導致效能問題,例如延遲物件記憶體的回收,或導致記憶體洩漏。 - 資源釋放:如果你在
finalize()
方法中處理類似於檔案關閉等操作,可能會導致資源無法及時釋放。如果你的應用程式開啟了大量檔案且依賴於finalize()
方法來關閉這些檔案,可能會導致資源耗盡,因為垃圾收集器沒有及時呼叫finalize()
方法。
因此,通常的最佳實踐是避免使用 finalize()
方法來清理資源。相反,推薦使用 try-with-resources 語句或者顯式的清理方法,例如,在你控制資源的程式碼塊中使用 try-catch-finally 來確保資源始終得到適當的釋放。
簡而言之,finalize()
方法可以看作是在物件生命週期結束前的 “最後通牒”,雖然你可以在這裡做一些清理工作,但它的執行是不可預測的,並且可能會給程式帶來更多問題,因此不建議依賴它來釋放資源或做其他關鍵操作。
finally
finally 是一個關鍵字,與 try 和 catch 一起用於異常的處理。finally 塊一定會被執行,無論在 try 塊中是否有發生異常。
想象一下,你在遊樂場玩拋球遊戲。try
塊就像是你向籃筐投球的嘗試,如果球進了籃筐,那就意味著沒有發生錯誤,你的程式碼執行正常。而如果球沒有進籃筐,這就好比發生了異常,這時候 catch
塊就會介入,像是遊戲工作人員過來告訴你什麼出了問題,並給你另一次機會。
現在,打個比方,無論你是否成功將球投入籃筐(即無論 try
塊中的程式碼是否成功執行),你都必須將球還給工作人員,這個動作就像是 finally
塊。finally
塊確保了無論之前發生了什麼,一些必須進行的清理工作(比如歸還球)都會被執行。這表示即便在 try
塊中程式碼順利執行或 catch
塊捕獲到異常後執行相應的錯誤處理程式碼,finally
塊中的程式碼也總是會被執行。這通常是用來釋放資源,比如關閉檔案流或資料庫連線。
簡言之,finally
是你整理遊戲場地,確保一切都已妥善處理後才離開的保障。它保證了,在你完成遊戲之後,不管結果如何,都會有一些後處理工作被執行以維持場地的正常運作。