final、finally與finalize的區別

  1. final

  在java中,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時,說明該參數是隻讀型的。即你可以讀取使用該參數,但是無法改變該參數的值。

final、finally與finalize的區別

   

  在java中,String被設計成final類,那爲什麼平時使用時,String的值可以被改變呢?

  字符串常量池是java堆內存中一個特殊的存儲區域,當我們建立一個String對象時,假設常量池不存在該字符串,則創建一個,若存在則直接引用已經存在的字符串。當我們對String對象值改變的時候,例如 String a="A"; a="B" 。a是String對象的一個引用(我們這裏所說的String對象其實是指字符串常量),當a=“B”執行時,並不是原本String對象("A")發生改變,而是創建一個新的對象("B"),令a引用它。

  1. finally

      finally作爲異常處理的一部分,它只能用在try/catch語句中,並且附帶一個語句塊,表示這段語句最終一定會被執行(不管有沒有拋出異常),經常被用在需要釋放資源的情況下。(×)(這句話其實存在一定的問題)

  很多人都認爲finally語句塊一定會執行,但真的是這樣麼?答案是否定的,例如下面這個例子:

  final、finally與finalize的區別

  當我們去掉註釋的三行語句,執行結果爲:
final、finally與finalize的區別
  

  爲什麼在以上兩種情況下都沒有執行finally語句呢,說明什麼問題?

  只有與finally對應的try語句塊得到執行的情況下,finally語句塊纔會執行。以上兩種情況在執行try語句塊之前已經返回或拋出異常,所以try對應的finally語句並沒有執行。

  但是,在某些情況下,即使try語句執行了,finally語句也不一定執行。例如以下情況:

  final、finally與finalize的區別

  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語句。我們看如下代碼:
final、finally與finalize的區別
  

  答案:4,4,4 。 爲什麼呢?

  首先finally語句在改代碼中一定會執行,從運行結果來看,每次return的結果都是4(即finally語句),彷彿其他return語句被屏蔽掉了。

  事實也確實如此,因爲finally用法特殊,所以會撤銷之前的return語句,繼續執行最後的finally塊中的代碼。

  

  1. finalize  

  finalize()是在java.lang.Object裏定義的,也就是說每一個對象都有這麼個方法。這個方法在gc啓動,該對象被回收的時候被調用。其實gc可以回收大部分的對象(凡是new出來的對象,gc都能搞定,一般情況下我們又不會用new以外的方式去創建對象),所以一般是不需要程序員去實現finalize的。
特殊情況下,需要程序員實現finalize,當對象被回收的時候釋放一些資源,比如:一個socket鏈接,在對象初始化時創建,整個生命週期內有效,那麼就需要實現finalize,關閉這個鏈接。
  使用finalize還需要注意一個事,調用super.finalize();

  一個對象的finalize()方法只會被調用一次,而且finalize()被調用不意味着gc會立即回收該對象,所以有可能調用finalize()後,該對象又不需要被回收了,然後到了真正要被回收的時候,因爲前面調用過一次,所以不會調用finalize(),產生問題。 所以,推薦不要使用finalize()方法,它跟析構函數不一樣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章