程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> JSP編程 >> 關於JSP >> java中final, finally, finalize的區別

java中final, finally, finalize的區別

編輯:關於JSP

       final—修飾符(關鍵字)如果一個類被聲明為final,意味著它不能再派生出新的子類,不能作為父類被繼承。因此一個類不能既被聲明為 abstract的,又被聲明為final的。將變量或方法聲明為final,可以保證它們在使用中不被改變。被聲明為final的變量必須在聲明時給定初值,而在以後的引用中只能讀取,不可修改。被聲明為final的方法也同樣只能使用,不能重載。

      final變量定義: 變量一經初始化就不能指向其它對象。指向的存儲地址不可修改,但指向的對象本身是可以修改的。

      先說final變量初始化:

      很多文章都這麼說:其初始化可以在兩個地方,一是其定義處,二是在構造函數中,兩者只能選其一。

      胡說八道!

      final變量可以在任何可以被始化的地方被始化,但只能被初始化一次.一旦被初始化後就不能再次賦

      值(重新指向其它對象),作為成員變量一定要顯式初始化,而作為臨時變量則可以只定義不初始化(當然也不能引用)

      即使是作為一個類中的成員變量,也還可以在初始化塊中初始化,所以"其初始化可以在兩個地方,一是其定義處,

      二是在構造函數中,兩者只能選其一"是錯誤的.

      作為成員變量時,final字段可以設計不變類,是不變類的一個必要條件但不是一個充要條件.至少可以保證字段不

      會以setXXX()這樣的方式來改變.但無法保證字段本身不被修改(除非字段本身也是不變類);

      對於方法參數的final變量:

      對於方法參數的變量定義為final,90%以上的文章都說"當你在方法中不需要改變作為參數的對象變量時,明確使

      用final進行聲明,會防止你無意的修改而影響到調用方法外的變量。"

      胡說八道!

      我不知道這個修改是說重新賦值還是修改對象本身,但無論是哪種情況,上面的說法都是錯誤的.

      如果是說重新賦值,那麼:

    代碼如下  

    public static void test(int[] x){
    x = new int[]{1,2,3};
    }

    int[] out = new int[]{4,5,6};
    test(out);
    System.out.println(out[0]);
    System.out.println(out[1]);
    System.out.println(out[2]);

      調用test(out);無論如何也不會影響到外面變量out.你加不加final根本沒有意義.final只會強迫方法內

      多聲明一個變量名而已,即把x = new int[]{1,2,3};改成int y = new int[]{1,2,3}; 其它沒有任何實際意義.

      如果說是修改對象本身:

    代碼如下   public static void test(final int[] x){
    x[0] = 100;
    }
    int[] out = new int[]{4,5,6};
    test(out);
    System.out.println(out[0]);

      難道你用final修飾就不可以修改了?所以說對於方法參數中final是為了不影響調用方法外的變量那是胡說八道的.

      那我們到底為什麼要對參數加上final?其實對方法參數加final和方法內變量加上final的作用是相同的,即為了將它們

      傳給內部類回調方法:

    代碼如下  

    abstract class ABSClass{
    public abstract void m();
    }

      現在我們來看,如果我要實現一個在一個方法中匿名調用ABSClass.應該:

    代碼如下  

    public static void test(String s){
    //或String s = "";
    ABSClass c = new ABSClass(){
    public void m(){
    int x = s.hashCode();

    System.out.println(x);

    }
    };
    //其它代碼.
    }

      注意這裡,一般而言,回調方法基本上是在其它線程中調用的.如果我們在上面的

    代碼如下  

    ABSClass c = new ABSClass(){
    public void m(){
    int x = s.hashCode();

    System.out.println(x);

    }
    };

      後面直接調用c.m();應該是沒有意義的.但這不重要,重要的是只要有可能是在其它線程中調用,那我們就必須

      為s保存引用句柄.

      我們先來看GC工作原理,JVM中每個進程都會有多個根,每個static變量,方法參數,局部變量,當然這都是指引用類型.

      基礎類型是不能作為根的,根其實就是一個存儲地址.

      GC在工作時先從根開始遍歷它引用的對象並標記它們,如此遞歸到最末梢,所有根都遍歷後,沒有被標記到的對象說明沒

      有被引用,那麼就是可以被回收的對象(有些對象有finalized方法,雖然沒有引用,但JVM中有一個專門的隊列引用它

      們直到finalized方法被執行後才從該隊列中移除成為真正沒有引用的對象,可以回收,這個與本主題討論的無關,包括

      代的劃分等以後再說明).這看起來很好.

      但是在內部類的回調方法中,s既不可能是靜態變量,也不是方法中的臨時變量,也不是方法參數,它不可能作為根,在內部類

      中也沒有變量引用它,它的根在內部類外部的那個方法中,如果這時外面變量重指向其它對象,則這個對象就失去了引用,

      可能被回收,而由於內部類回調方法大多數在其它線程中執行,可能還要在回收後還會繼續訪問它.這將是什麼結果?

      而使用final修飾符不僅會保持對象不會改變,而且編譯器還會持續維護這個對象在回調方法中的生命周期.所以這才是final

      變量和final參數的根本意義.

      finally—再異常處理時提供 finally 塊來執行任何清除操作。如果拋出一個異常,那麼相匹配的 catch子句就會執行,然後控制就會進入 finally 塊(如果有的話)。

      我們翻遍上古秘籍,最終在北京山頂洞人的失傳寶典《呼呼,擦!》中發現了一個據稱絕對干淨的擦法,那就是------------

      一下一下擦!

      具體操作辦法如下:

      代碼

    代碼如下   void f(){
    final Connection conn = ...;
    try{
    final Statement stmt = ...;
    try{
    final ResultSet rset = ...;
    try{
    ...
    }
    finally{rset.close();}
    }
    finally{stmt.close();}
    }
    finally{conn.close();}
    }

      其訣竅就是,每建立一個需要清理的資源,就用一個try-finally來保證它可以被清理掉。

      如此,任何時候,你都是屁股干干靜靜地離開衛生間。

      哪。好多聖人門徒跟我說:這樣一下一下擦,姿勢非常不雅觀(看看那嵌套的try塊吧),有違古禮。我們反對!

      靠,你說孔丑兒古還是山頂洞人古??

      屁股還泛著味兒呢,還拽什麼“雅”?

      而且,要是死要面子,也可以拉個簾子,擦的時候別讓人看見嘛。比如:

      代碼

    代碼如下  

    interface ResultListener{
    void call(ResultSet rset);
    }
    class SqlReader{
    void read(ResultListener l){
    final Connection conn = ...;
    try{
    final Statement stmt = ...;
    try{
    final ResultSet rset = ...;
    try{
    l.call(rset);
    }
    finally{rset.close();}
    }
    finally{stmt.close();}
    }
    finally{conn.close();}
    }
    }

     

      finalize—方法名。

      finalize相當於析構函數,他是垃圾回收器回收一個對象的時候第一個要調用的方法。不過由於Java的垃圾回收機制能自動為我們做這些事情,所以我們在一般情況下是不需要自己來手工釋放的。

      有時當撤消一個對象時,需要完成一些操作。例如,如果一個對象正在處理的是非Java 資源,如文件句柄或window 字符字體,這時你要確認在一個對象被撤消以前要保證這些資源被釋放。為處理這樣的狀況,Java 提供了被稱為收尾(finalization )的機制。使用該機制你可以定義一些特殊的操作,這些操作在一個對象將要被垃圾回收程序釋放時執行。

      要給一個類增加收尾(finalizer ),你只要定義finalize ( ) 方法即可。Java 回收該類的一個對象時,就會調用這個方法。在finalize ( )方法中,你要指定在一個對象被撤消前必須執行的操作。垃圾回收周期性地運行,檢查對象不再被運行狀態引用或間接地通過其他對象引用。就在對象被釋放之 前,Java 運行系統調用該對象的finalize( ) 方法。

      finalize()方法的通用格式如下:

    代碼如下  

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

      其中,關鍵字protected是防止在該類之外定義的代碼訪問finalize()標識符。該標識符和其他標識符將在第7章中解釋。

      理解finalize( ) 正好在垃圾回收以前被調用非常重要。例如當一個對象超出了它的作用域時,finalize( ) 並不被調用。這意味著你不可能知道何時——甚至是否——finalize( ) 被調用。因此,你的程序應該提供其他的方法來釋放由對象使用的系統資源,而不能依靠finalize( ) 來完成程序的正常操作。

      注意:如果你熟悉C++,那你知道C++允許你為一個類定義一個撤消函數(destructor ),它在對象正好出作用域之前被調用。Java不支持這個想法也不提供撤消函數。finalize() 方法只和撤消函數的功能接近。當你對Java 有豐富經驗時,你將看到因為Java使用垃圾回收子系統,幾乎沒有必要使用撤消函數。

      finalize的工作原理應該是這樣的:一旦垃圾收集器准備好釋放對象占用的存儲空間,它首先調用finalize(),而且只有在下一次垃圾收集過程中,才會真正回收對象的內存.所以如果使用finalize(),就可以在垃圾收集期間進行一些重要的清除或清掃工作.

      finalize()在什麼時候被調用?

      有三種情況

      1.所有對象被Garbage Collection時自動調用,比如運行System.gc()的時候.

      2.程序退出時為每個對象調用一次finalize方法。

      3.顯式的調用finalize方法

      除此以外,正常情況下,當某個對象被系統收集為無用信息的時候,finalize()將被自動調用,但是jvm不保證finalize()一定被調用,也就是說,finalize()的調用是不確定的,這也就是為什麼sun不提倡使用finalize()的原因

      有時當撤消一個對象時,需要完成一些操作。例如,如果一個對象正在處理的是非Java 資源,如文件句柄或window 字符字體,這時你要確認在一個對象被撤消以前要保證這些資源被釋放。為處理這樣的狀況,Java 提供了被稱為收尾(finalization )的機制。使用該機制你可以定義一些特殊的操作,這些操作在一個對象將要被垃圾回收程序釋放時執行。

      要給一個類增加收尾(finalizer ),你只要定義finalize ( ) 方法即可。Java 回收該類的一個對象時,就會調用這個方法。在finalize ( )方法中,你要指定在一個對象被撤消前必須執行的操作。垃圾回收周期性地運行,檢查對象不再被運行狀態引用或間接地通過其他對象引用。就在對象被釋放之 前,Java 運行系統調用該對象的finalize( ) 方法。

      finalize()方法的通用格式如下:

    代碼如下  

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

      其中,關鍵字protected是防止在該類之外定義的代碼訪問finalize()標識符。該標識符和其他標識符將在第7章中解釋。

      理解finalize( ) 正好在垃圾回收以前被調用非常重要。例如當一個對象超出了它的作用域時,finalize( ) 並不被調用。這意味著你不可能知道何時——甚至是否——finalize( ) 被調用。因此,你的程序應該提供其他的方法來釋放由對象使用的系統資源,而不能依靠finalize( ) 來完成程序的正常操作。

      Java 技術允許使用 finalize() 方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。當垃圾回收器確定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。finalize() 方法是在垃圾收集器刪除對象之前對這個對象調用的。

    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved