1. 程式人生 > >知識點幹貨--講一講final、finally、finalize的區別

知識點幹貨--講一講final、finally、finalize的區別

匹配 main object類 作用域 mage 一次 推送 AC 以及

“橫看成嶺側成峰,遠近高低各不同。不識廬山真面目,只緣身在此山中。”
這首詩來自於宋朝蘇軾《題西林壁》,它的意思是,廬山從正面看,它是一道道連綿起伏的山嶺;從側面看,它是一座巍然聳立的險峰,而從遠處、近處、高處、低處看,廬山又呈現各種不同的樣子。
我們之所以認不清廬山真正的面目,是因為人身處在廬山之中。詩的意思是指同一個事物在不同的角度和不同的時間看是不一樣的,指出我們在看待或者觀察問題時應當客觀全面,如果主觀片面的看問題,就會得出不正確的結論。

final、finally、finalize這三個關鍵字長得很像,對於Android初學者或者Java初學者來說容易混淆,有時分不清楚該怎樣正確的使用它們,並且它們也經常是某些公司面試基礎知識中的重點,所以我們有必要來專項學習一下它。今天我就來總結一下它們的定義,使用場景,區別等,爭取把它們所有相關的知識點都一次性講明白,使大家都能夠很好的掌握它們。

1、關於final

final是Java中的一個修飾關鍵字,它可以用來修改類,方法和變量。
(1)、如果用它來修飾類,即類被聲明為final,意味著這個類不能再派生出新的子類,不能作為父類被繼承。例如,String、StringBuilder、StringBuffer、Math等類。它和abstract(抽象)是互斥的,用abstract修飾的類是必須要繼承才能實例化對象的,因此一個類不能既被聲明為 abstract,又被聲明為final。
(2)、而用final修飾變量或方法時,可以保證變量或方法在使用中不被改變。
被final修飾的變量必須在聲明時給定初值,而在以後的使用中只能讀取,不可修改,場景包括形參,局部變量,成員變量等情況。如果修飾的是基本數據類型,則初始化之後變量的值不能被改變;如果修飾的變量是引用類型,那麽它只能指向初始化時指向的那個對象,不能再指向別的對象,但是對象當中的內容是允許改變的。
(3)、被final修飾的方法也同樣只能使用,不能被重載,但是子類可以使用或調用父類中final修飾的方法。
(4)、final有一個特殊的使用場景。
當方法內部聲明的類或者方法內定義的匿名內部類,訪問該方法內定義的局部變量時,該變量必須要用final修飾。因為當內部類或內部匿名類訪問方法的局部變量時,相當於擴大了局部變量的作用域,如果局部變量不用 final 修飾,我們就可以在內部類中隨意修改該局部變量值,而在該局部變量的作用域範圍之外是可以看到這些修改後的值,這樣將會出現安全問題,所以必須用final修飾,不允許內部類或內部匿名類修改變量的值。而方法內部類或內部匿名類在訪問該方法所在的類的成員變量時,卻可以不用final修飾。

如下所示,

public class TestFinal {
    String str1 = "no need final";
    //匿名內部類
    public void testAnonyClass() {
        final String str2 = "need final";

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(str1);
                System.out.println(str2);

            }
        }).start();
    }

    public void testInnerClass(){
        final String str3 = "also need final";
        //方法內部定義的內部類
        class innerClass{
            public void method1(){
                System.out.println(str1);
                System.out.println(str3);
            }
        }
    }
}

如上所示str2在方法testAnonyClass中的匿名類中訪問,它需要聲明為final類型才可以,str3在方法testInnerClass中的內部類innerClass中訪問,也同樣需要聲明為final。這兩個方法中的內部類或內部匿名類在訪問方法所在的類中的成員變量str1時,str1不需要聲明為final。

2、關於finally

finally也是Java中的一個保留字,用在異常處理時,提供 finally代碼塊來執行最後的清除操作。
我們在寫一段可能拋出異常的代碼段時,如果我們希望捕獲這個代碼段中拋出的異常,那我們一般這樣來寫,

try {
    //調用方法,期間可能拋出異常
    //....
} catch (Exception e) {
    e.printStackTrace();
} finally {
    //可以進行一些清理
    //....
}

如果拋出一個異常,那麽相匹配的 catch 子句就會執行,然後最終控制會進入 finally代碼塊。
finally語句不會被執行的唯一情況是:先執行了用於終止程序的System.exit()方法,這個時候不會走到finally語句中,或者如果在執行過程中突然斷電了,這時所有進程都會終止,也不會執行finally語句。

大家看一下如下demo,猜一猜打印的結果是什麽?

public class TestFinally{
    public int testFinally(){
        try{
            System.out.println("-----try-----");
            return 1;
        }finally{
            System.out.println("-----finally-----");
            return 2 ;
        }
    }
    public static void main(String[]args){
        TestFinally te= new TestFinally();
        int t = te.testFinally();
        System.out.println(t);
      }
}

這裏有兩個return,按正常邏輯在try中調用return後,方法就返回了,但是因為下面有finally語句,並且其中也有一個return,所以最終應該返回finally語句中return對應的結果。
以上程序運行結果如下所示,
-----try-----
-----finally-----
2
如果註釋掉finally語句中return,返回結果如下所示,
-----try-----
-----finally-----
1
可見finally中的語句永遠都是要執行的。

3、關於finalize

finalize是Java中的一個方法名,它在Object類中定義,因此所有的類都繼承了它。finalize() 方法的作用是在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。垃圾收集器在確定這個對象沒有被引用時將調用此對象的finalize()方法,或者說finalize() 方法是在垃圾收集器刪除對象之前對這個對象調用的。子類可以覆蓋finalize() 方法從而整理自己定義的各類資源,或者執行資源清理工作。

使用場景,當銷毀一個對象時,需要執行一些額外操作。例如,如果一個對象創建了一些非Java 資源,如文件句柄,window 字符字體或者數據庫cursor等,這時你在這個對象被銷毀前,要保證這些資源被安全釋放。那如何保證呢?Java提供了一種收尾(finalization)機制,可以通過重寫finalize() 方法來實現這種機制,在這種機制或者finalize() 方法中,可以將對象在進行垃圾回收前釋放之前創建的其它資源。
在finalize ( )方法中,你要指定這個對象被撤消前必須執行的操作。系統的垃圾回收會周期性地運行,將由JVM的垃圾回收機制來控制,它會檢查此對象是不是不再被運行狀態引用或間接地引用。如果沒有被引用,將會釋放此對象,對應的inalize( ) 方法就會執行。

finalize()方法定義如下所示:

protected void finalize( )
{
// finalization code here
}

但是,finalize( )並不確保一個對象超出了它的作用域時就會執行,也就是說你不可能知道何時,甚至是否finalize( ) 被調用,因為這完全取決於系統的垃圾回收機制。所以,釋放對象所創建的資源最好使用其它方法來實現,而不能僅僅依靠finalize( ) 來完成程序的資源釋放工作。

finalize()在什麽場景使用呢?
有三種情況

(1)、對象沒有了直接和間接引用,垃圾回收器(garbage colector)決定回收某對象時,比如運行System.gc()的時候。

(2)、程序退出時為對象調用一次finalize方法。

(3)、顯式的調用finalize方法。`

4、總結

由以上介紹,我們應該對final、finally、finalize有所了解了。對於它們的使用,還需要我們在工作中多摸索和多實踐,這樣才會理解的更加深刻,運用起來才會得心應手,才不會對它們產生混淆。

技術分享圖片
本公眾號將以推送Android各種技術幹貨或碎片化知識,以及整理老司機日常工作中踩過的坑涉及到的經驗知識為主,也會不定期將正在學習使用的新技術總結出來進行分享。每天一點幹貨小知識把你的碎片時間充分利用起來。

知識點幹貨--講一講final、finally、finalize的區別