萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> jsp編程 >> java中final, finally, finalize的區別

java中final, finally, finalize的區別

   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塊吧),有違古禮。我們反對!

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

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

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

  代碼

代碼如下  

copyright © 萬盛學電腦網 all rights reserved