Java中final、finally、finalize的區別和用法
1.簡單區別
- final用於宣告屬性,方法和類,分別表示屬性不可交變,方法不可覆蓋,類不可繼承。
- finally是異常處理語句結構的一部分,表示總是執行。
- finalize是Object類的一個方法,在垃圾收集器執行的時候會呼叫被回收物件的此方法,供垃圾收集時的其他資源回收,例如關閉檔案等。
2.中等區別
- 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:final關鍵字我們首先來說說final。它可以用於以下四個地方:
1).定義變數,包括靜態的和非靜態的。
2).定義方法的引數。
3).定義方法。
4).定義類。
(1)定義變數
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;
}
(2)定義方法:當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();
}
}
(3)定義類: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);
}
}
- 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這個可以打亂程式碼順序執行語句的規律。
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語句 1 con 執行了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的用法區別已經很清楚了。