Java中final、finally、finalize的區別與用法,finalfinalize

來源:互聯網
上載者:User

Java中final、finally、finalize的區別與用法,finalfinalize

1.簡單區別:
final用於聲明屬性,方法和類,分別表示屬性不可交變,方法不可覆蓋,類不可繼承。
finally是異常處理語句結構的一部分,表示總是執行。
finalize是Object類的一個方法,在垃圾收集器執行的時候會調用被回收對象的此方法,供垃圾收集時的其他資源回收,例如關閉檔案等。
2.中等區別:
雖然這個單詞在Java中都存在,但是並沒太多關聯:
final:java中的關鍵字,修飾符。
A).如果一個類被聲明為final,就意味著它不能再派生出新的子類,不能作為父類被繼承。因此,一個類不能同時被聲明為abstract抽象類別的和final的類。
B).如果將變數或者方法聲明為final,可以保證它們在使用中不被改變.
  1)被聲明為final的變數必須在聲明時給定初值,而在以後的引用中只能讀取,不可修改。
  2)被聲明final的方法只能使用,不能重載。
finally:java的一種異常處理機制。
  finally是對Java異常處理模型的最佳補充。finally結構使代碼總會執行,而不管無異常發生。使用finally可以維護對象的內部狀態,並可以清理非記憶體資源。特別是在關閉資料庫連接這方面,如果程式員把資料庫連接的close()方法放到finally中,就會大大降低程式出錯的幾率。
finalize:Java中的一個方法名。
Java技術使用finalize()方法在垃圾收集器將對象從記憶體中清除出去前,做必要的清理工作。這個方法是由垃圾收集器在確定這個對象沒被引用時對這個對象調用的。它是在Object類中定義的,因此所的類都繼承了它。子類覆蓋finalize()方法以整理系統資源或者執行其他清理工作。finalize()方法是在垃圾收集器刪除對象之前對這個對象調用的。
3.詳細區別:
這是一道再經典不過的面試題了,我們在各個公司的面試題中幾乎都能看到它的身影。final、finally和finalize雖然長得像孿生兄弟一樣,但是它們的含義和用法卻是大相徑庭。
final關鍵字我們首先來說說final。它可以用於以下四個地方:
1).定義變數,包括靜態和非靜態。
2).定義方法的參數。
3).定義方法。
4).定義類。
定義變數,包括靜態和非靜態。定義方法的參數
第一種情況:
  如果final修飾的是一個基本類型,就表示這個變數被賦予的值是不可變的,即它是個常量;
  如果final修飾的是一個對象,就表示這個變數被賦予的引用是不可變的
這裡需要提醒大家注意的是,不可改變的只是這個變數所儲存的引用,並不是這個引用所指向的對象。
第二種情況:final的含義與第一種情況相同。
實際上對於前兩種情況,一種更貼切的表述final的含義的描述,那就是,如果一個變數或方法參數被final修飾,就表示它只能被賦值一次,但是JAVA虛擬機器為變數設定的預設值不記作一次賦值。被final修飾的變數必須被初始化。初始化的方式以下幾種:    
1.在定義的時候初始化。    
2.final變數可以在初始化塊中初始化,不可以在靜態初始化塊中初始化。
3.靜態final變數可以在定義時初始化,也可以在靜態初始化塊中初始化,不可以在初始化塊中初始化。    
4.final變數還可以在類的構造器中初始化,但是靜態final變數不可以。
通過下面的代碼可以驗證以上的觀點:

public class FinalTest{  public final int A=10; //在定義時初始化  public final int B;{B=20;} //在初始化塊中初始化  //非靜態final變數不能在靜態初始化塊中初始化      //public final int C;static{//C=30; }  //靜態常量,在定義時初始化  public static final int STATIC_D=40;   //靜態常量,在靜態初始化塊中初始化  public static final int STATIC_E;static{STATIC_E = 50;}  //靜態變數不能在初始化塊中初始化      //public static final int  STATIC_F;{STATIC_F=60;}  public final int G;  //靜態final變數不可以在構造器中初始化      //public static final int STATIC_H;  //在構造器中初始化           public finalTest(){    G=70;    //靜態final變數不可以在構造器中初始化    //STATIC_H=80;    //給final的變數第二次賦值時,編譯會報錯    //A=99;    //STATIC_D=99;  }  //final變數未被初始化,編譯時間就會報錯  //public final int L;  //靜態final變數未被初始化,編譯時間就會報錯  //public static final int STATIC_J;}

我們運行上面的代碼之後出了可以發現final變數(常量和靜態final變數(靜態常量被初始化時,編譯會報錯。
用final修飾的變數(常量比非final的變數(普通變數擁更高的效率,因此我們在際編程中應該儘可能多的用常量來代替普通變數。
定義方法
當final用來定義一個方法時,它表示這個方法不可以被子類重寫,但是並不影響它被子類繼承。我們寫段代碼來驗證一下:

public class ParentClass{    public final void TestFinal(){        System.out.println("父類--這是一個final方法");    }}public class SubClass extends ParentClass{    //子類無法重寫(override父類的final方法,否則編譯時間會報錯    /* public void TestFinal(){           System.out.println("子類--重寫final方法");    } */       public static void main(String[]args){        SubClass sc = new SubClass();        sc.TestFinal();    }}    

這裡需要特殊說明的是,具有private存取權限的方法也可以增加final修飾,但是由於子類無法繼承private方法,因此也無法重寫它。編譯器在處理private方法時,是照final方來對待的,這樣可以提高該方法被調用時的效率。不過子類仍然可以定義同父類中private方法具同樣結構的方法,但是這並不會產生重寫的效果,而且它們之間也不存在必然聯絡。
定義類
最後我們再來回顧一下final用於類的情況。這個大家應該也很熟悉了,因為我們最常用的String類就是final的。由於final類不允許被繼承,編譯器在處理時把它的所方法都當作final的,因此final類比普通類擁更高的效率。而由關鍵字abstract定義的抽象類別含必須由繼承自它的子類重載實現的抽象方法,因此無法同時用final和abstract來修飾同一個類。同樣的道理,
final也不能用來修飾介面。 final的類的所方法都不能被重寫,但這並不表示final的類的屬性(變數值也是不可改變的,要想做到final類的屬性值不可改變,必須給它增加final修飾,請看下面的例子:

public final class FinalTest{    int i =20;    final int j=50;    public static void main(String[] args){          FinalTest ft = new FinalTest();          ft.i = 99;/*final類FinalTest的屬性值 i是可以改變的,因為屬性值i前面沒final修飾*/          //ft.j=49;//報錯....因為j屬性是final的不可以改變。          System.out.println(ft.i);    }}        

運行上面的代碼試試看,結果是99,而不是初始化時的10。
finally語句
接下來我們一起回顧一下finally的用法。finally只能用在try/catch語句中並且附帶著一個語句塊,表示這段語句最終總是被執行。請看下面的代碼:

public final class FinallyTest{    public static void main(String[] args){        try{            throw new NullPointerException();        }catch(NullPointerException e){            System.out.println("程式拋出了異常");        }finally{            //這裡總會被執行,不受break,return影響另如資料庫連接的close()一般寫在這裡,可以降低程式的出錯幾率            System.out.println("執行了finally語句塊");        }    }}

運行結果說明了finally的作用:

1.程式拋出了異常

2.執行了finally語句塊請大家注意,捕獲程式拋出的異常之後,既不加處理,也不繼續向上拋出異常,並不是良好的編程習慣,它掩蓋了程式執行中發生的錯誤,這裡只是方便示範,請不要學習。
那麼,沒一種情況使finally語句塊得不到執行呢?
return、continue、break這個可以打亂代碼順序執行語句的規律。那我們就來試試看,這個語句是否能影響finally語句塊的執行:

public final class FinallyTest {    //測試return語句    //結果顯示:編譯器在編譯return new ReturnClass();時,    //將它分成了兩個步驟,new ReturnClass()和return,前一個建立對象的語句是在finally語句塊之前被執行的,    //而後一個return語句是在finally語句塊之後執行的,也就是說finally語句塊是在程式退出方法之前被執行的    public ReturnClass testReturn() {        try {            return new ReturnClass();        } catch (Exception e) {            e.printStackTrace();        } finally {            System.out.println("執行了finally語句");        }        return null;    }    //測試continue語句    public void testContinue(){        for(int i=0; i<3; i++){            try {                System.out.println(i);                if(i == 1){                    System.out.println("con");                }            } catch(Exception e) {                e.printStackTrace();            } finally {                System.out.println("執行了finally語句");            }        }    }    //測試break語句    public void testBreak() {        for (int i=0; i<3; i++) {            try {                System.out.println(i);                if (i == 1) {                    break;                }            } catch (Exception e) {                e.printStackTrace();            } finally {                System.out.println("執行了finally語句");            }        }    }    public static void main(String[] args) {        FinallyTest ft = new FinallyTest();        // 測試return語句        ft.testReturn();        System.out.println();        // 測試continue語句        ft.testContinue();        System.out.println();        // 測試break語句        ft.testBreak();    }}class ReturnClass {    public ReturnClass() {        System.out.println("執行了return語句");    }}
上面這段代碼的運行結果如下:
執行了return語句執行了finally語句0執行了finally語句1con執行了finally語句2執行了finally語句0執行了finally語句1執行了finally語句

很明顯,return、continue和break都沒能阻止finally語句塊的執行。從輸出的結果來看,return語句似乎在finally語句塊之前執行了,事實真的如此嗎?我們來想想看,return語句的作用是什麼呢?是退出當前的方法,並將值或對象返回。如果 finally語句塊是在return語句之後執行的,那麼return語句被執行後就已經退出當前方法了,finally語句塊又如何能被執行呢?因此,正確的執行順序應該是這樣的:編譯器在編譯return new ReturnClass();時,將它分成了兩個步驟,new ReturnClass()和return,前一個建立對象的語句是在finally語句塊之前被執行的,而後一個return語句是在finally語句塊之後執行的,也就是說finally語句塊是在程式退出方法之前被執行的。同樣,finally語句塊是在迴圈被跳過(continue和中斷(break之前被執行的
finalize方法
最後,我們再來看看finalize,它是一個方法,屬於java.lang.Object類,它的定義如下:protected void finalize()throws Throwable{}眾所周知,finalize()方法是GC(garbagecollector運行機制的一部分,在此我們只說說finalize()方法的作用是什麼呢?finalize()方法是在GC清理它所從屬的對象時被調用的,如果執行它的過程中拋出了無法捕獲的異常(uncaughtexception,GC將終止對改對象的清理,並且該異常會被忽略;直到下一次GC開始清理這個對象時,它的finalize()會被再次調用。請看下面的樣本:

public final class FinallyTest{    //重寫finalize()方法    protected void finalize() throws Throwable{         System.out.println("執行了finalize()方法");    }    public static void main(String[] args){          FinallyTest ft = new FinallyTest();          ft = null;          System.gc();    }}

運行結果如下:• 執行了finalize()方法
程式調用了java.lang.System類的gc()方法,引起GC的執行,GC在清理ft對象時調用了它的finalize()方法,因此才了上面的輸出結果。調用System.gc()等同於調用下面這行代碼:Runtime.getRuntime().gc();調用它們的作用只是建議垃圾收集器(GC啟動,清理無用的對象釋放記憶體空間,但是GC的啟動並不是一定的,這由JAVA虛擬機器來決定。直到 JAVA虛擬機器停止運行,些對象的finalize()可能都沒被運行過,那麼怎樣保證所對象的這個方法在JAVA虛擬機器停止運行之前一定被調用呢?答案是我們可以調用System類的另一個方法:

public static void FunFinalizersOnExit(boolean value){    //othercode}  

給這個方法傳入true就可以保證對象的finalize()方法在JAVA虛擬機器停止運行前一定被運行了,不過遺憾的是這個方法是不安全的,它會導致有用的對象finalize()被誤調用,因此已不被贊成使用了。由於finalize()屬於Object類,因此所類都這個方法,Object的任意子類都可以重寫(override該方法,在其中釋放系統資源或者做其它的清理工作,如關閉輸入輸出資料流。通過以上知識的回顧,我想大家對於final、finally、finalize的用法區別已經很清楚了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.