final、finally、finalize的區別
1、final修飾符(關鍵字)。被final修飾的類,就意味著不能再派生出新的子類,不能作為父類而被子類繼承。因此一個類不能既被abstract聲明,又被final聲明。將變量或方法聲明為final,可以保證他們在使用的過程中不被修改。被聲明為final的變量必須在聲明時給出變量的初始值,而在以後的引用中只能讀取。被final聲明的方法也同樣只能使用,不能重載。
1.1 修飾類
當用final修飾類的時,表明該類不能被其他類所繼承。當我們需要讓一個類永遠不被繼承,此時就可以用final修飾,但要註意:
final類中所有的成員方法都會隱式的定義為final方法。
1.2 修飾方法
使用final方法的原因主要有兩個:
(1) 把方法鎖定,以防止繼承類對其進行更改。
(2) 效率,在早期的java版本中,會將final方法轉為內嵌調用。但若方法過於龐大,可能在性能上不會有多大提升。因此在最近版本中,不需要final方法進行這些優化了。
final方法意味著“最後的、最終的”含義,即此方法不能被重寫。
註意:若父類中final方法的訪問權限為private,將導致子類中不能直接繼承該方法,因此,此時可以在子類中定義相同方法名的函數,此時不會與重寫final的矛盾,而是在子類中重新地定義了新方法。
class A{ private final void getName(){ } }public class B extends A{ public void getName(){ } public static void main(String[]args){ System.out.println("OK"); } }
1.3 修飾變量
final成員變量表示常量,只能被賦值一次,賦值後其值不再改變。類似於C++中的const。
當final修飾一個基本數據類型時,表示該基本數據類型的值一旦在初始化後便不能發生變化;如果final修飾一個引用類型時,則在對其初始化之後便不能再讓其指向其他對象了,但該引用所指向的對象的內容是可以發生變化的。本質上是一回事,因為引用的值是一個地址,final要求值,即地址的值不發生變化。
final修飾一個成員變量(屬性),必須要顯示初始化。這裏有兩種初始化方式,一種是在變量聲明的時候初始化;第二種方法是在聲明變量的時候不賦初值,但是要在這個變量所在的類的所有的構造函數中對這個變量賦初值。
當函數的參數類型聲明為final時,說明該參數是只讀型的。即你可以讀取使用該參數,但是無法改變該參數的值。
在java中,String被設計成final類,那為什麽平時使用時,String的值可以被改變呢?
字符串常量池是java堆內存中一個特殊的存儲區域,當我們建立一個String對象時,假設常量池不存在該字符串,則創建一個,若存在則直接引用已經存在的字符串。當我們對String對象值改變的時候,例如 String a="A"; a="B" 。a是String對象的一個引用(我們這裏所說的String對象其實是指字符串常量),當a=“B”執行時,並不是原本String對象("A")發生改變,而是創建一個新的對象("B"),令a引用它。
2、finally是在異常處理時提供finally塊來執行任何清除操作。不管有沒有異常被拋出、捕獲,finally塊都會被執行。try塊中的內容是在無異常時執行到結束。catch塊中的內容,是在try塊內容發生catch所聲明的異常時,跳轉到catch塊中執行。finally塊則是無論異常是否發生,都會執行finally塊的內容,所以在代碼邏輯中有需要無論發生什麽都必須執行的代碼,就可以放在finally塊中。
finally作為異常處理的一部分,它只能用在try/catch語句中,並且附帶一個語句塊,表示這段語句最終一定會被執行(不管有沒有拋出異常),經常被用在需要釋放資源的情況下。(×)(這句話其實存在一定的問題)
很多人都認為finally語句塊一定會執行,但真的是這樣麽?答案是否定的,例如下面這個例子:
為什麽在以上兩種情況下都沒有執行finally語句呢,說明什麽問題?
只有與finally對應的try語句塊得到執行的情況下,finally語句塊才會執行。以上兩種情況在執行try語句塊之前已經返回或拋出異常,所以try對應的finally語句並沒有執行。
但是,在某些情況下,即使try語句執行了,finally語句也不一定執行。例如以下情況:
finally 語句塊還是沒有執行,為什麽呢?因為我們在 try 語句塊中執行了 System.exit (0) 語句,終止了 Java 虛擬機的運行。那有人說了,在一般的 Java 應用中基本上是不會調用這個 System.exit(0) 方法的。OK !沒有問題,我們不調用 System.exit(0) 這個方法,那麽 finally 語句塊就一定會執行嗎?
再一次讓大家失望了,答案還是否定的。當一個線程在執行 try 語句塊或者 catch 語句塊時被打斷(interrupted)或者被終止(killed),與其相對應的 finally 語句塊可能不會執行。還有更極端的情況,就是在線程運行 try 語句塊或者 catch 語句塊時,突然死機或者斷電,finally 語句塊肯定不會執行了。可能有人認為死機、斷電這些理由有些強詞奪理,沒有關系,我們只是為了說明這個問題。
易錯點
在try-catch-finally語句中執行return語句。我們看如下代碼:
答案:4,4,4 。 為什麽呢?
首先finally語句在改代碼中一定會執行,從運行結果來看,每次return的結果都是4(即finally語句),仿佛其他return語句被屏蔽掉了。
事實也確實如此,因為finally用法特殊,所以會撤銷之前的return語句,繼續執行最後的finally塊中的代碼。
unlock鎖要寫在finally裏
3、finalize是方法名。java技術允許使用finalize()方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在確定這個對象沒有被引用時對這個對象調用的。它是在object類中定義的,因此所有的類都繼承了它。子類覆蓋finalize()方法以整理系統資源或者被執行其他清理工作。finalize()方法是在垃圾收集器刪除對象之前對這個對象調用的。
finalize()是在java.lang.Object裏定義的,也就是說每一個對象都有這麽個方法。這個方法在gc啟動,該對象被回收的時候被調用。其實gc可以回收大部分的對象(凡是new出來的對象,gc都能搞定,一般情況下我們又不會用new以外的方式去創建對象),所以一般是不需要程序員去實現finalize的。
特殊情況下,需要程序員實現finalize,當對象被回收的時候釋放一些資源,比如:一個socket鏈接,在對象初始化時創建,整個生命周期內有效,那麽就需要實現finalize,關閉這個鏈接。
使用finalize還需要註意一個事,調用super.finalize();
一個對象的finalize()方法只會被調用一次,而且finalize()被調用不意味著gc會立即回收該對象,所以有可能調用finalize()後,該對象又不需要被回收了,然後到了真正要被回收的時候,因為前面調用過一次,所以不會調用finalize(),產生問題。 所以,推薦不要使用finalize()方法,它跟析構函數不一樣。
final、finally、finalize的區別