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){難道你用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(){其訣竅就是,每建立一個需要清理的資源,就用一個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() 方法是在垃圾收集器刪除對象之前對這個對象調用的。