天天看點

【面試題】final, finally, finalize 的差別finalfinalyfinalize

目錄

final

修飾類

修飾方法

修飾變量

finaly

易錯點

finalize

final

在java中,final可以用來修飾類,方法和變量(成員變量或局部變量)。

修飾類

當用final修飾類的時,表明該類不能被其他類所繼承。當我們需要讓一個類永遠不被繼承,此時就可以用final修飾,但要注意:final類中所有的成員方法都會隐式的定義為final方法。

修飾方法

使用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");
    }
}
           

修飾變量

final成員變量表示常量,隻能被指派一次,指派後其值不再改變。類似于C++中的const。

當final修飾一個基本資料類型時,表示該基本資料類型的值一旦在初始化後便不能發生變化;如果final修飾一個引用類型時,則在對其初始化之後便不能再讓其指向其他對象了,但該引用所指向的對象的内容是可以發生變化的。本質上是一回事,因為引用的值是一個位址,final要求值,即位址的值不發生變化。

final修飾一個成員變量(屬性),必須要顯示初始化。這裡有兩種初始化方式,一種是在變量聲明的時候初始化;第二種方法是在聲明變量的時候不賦初值,但是要在這個變量所在的類的所有的構造函數中對這個變量賦初值。

當函數的參數類型聲明為final時,說明該參數是隻讀型的。即你可以讀取使用該參數,但是無法改變該參數的值。

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

finaly

【面試題】final, finally, finalize 的差別finalfinalyfinalize

 當我們去掉注釋的三行語句,執行結果為:

【面試題】final, finally, finalize 的差別finalfinalyfinalize

隻有與finally對應的try語句塊得到執行的情況下,finally語句塊才會執行。以上兩種情況在執行try語句塊之前已經傳回或抛出異常,是以try對應的finally語句并沒有執行。 

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

【面試題】final, finally, finalize 的差別finalfinalyfinalize

 finally仍然沒有執行,由于在 try 語句塊中執行了 System.exit (0) 語句,終止了Java 虛拟機的運作。

當一個線程在執行 try 語句塊或者 catch 語句塊時被打斷(interrupted)或者被終止(killed),與其相對應的 finally 語句塊可能不會執行。還有更極端的情況,就是線上程運作 try 語句塊或者 catch 語句塊時,突然當機或者斷電,finally 語句塊肯定不會執行了。

易錯點

在try-catch-finally語句中執行return語句。如下代碼:

【面試題】final, finally, finalize 的差別finalfinalyfinalize

答案:4,4,4

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

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

finalize

finalize()是在java.lang.Object裡定義的,也就是說每一個對象都有這麼個方法。這個方法在gc啟動,該對象被回收的時候被調用。其實gc可以回收大部分的對象(凡是new出來的對象,gc都能搞定,一般情況下我們又不會用new以外的方式去建立對象),是以一般是不需要程式員去實作finalize的。

特殊情況下,需要程式員實作finalize,當對象被回收的時候釋放一些資源,比如:一個socket連結,在對象初始化時建立,整個生命周期内有效,那麼就需要實作finalize,關閉這個連結。

使用finalize還需要注意一個事,調用super.finalize();

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