final, finally, finalize 的區別


雖然這個三個單詞在 Java 中都存在,但是並沒太多關聯:
1)final:java 中的關鍵字,修飾符、方法、變量。
2)finally:java 的一種異常處理機制。
3)finalize:Java中的一個方法名。
具體用法說明如下:

1 final 用法

在 java 中,final 可以用來修飾類,方法和變量(成員變量或局部變量)。
下面將對其詳細介紹。

1.1 final 修飾類

如果一個類被聲明爲final,就意味着它不能再派生出新的子類,不能作爲父類被繼承。因此:

  • 當我們需要讓一個類永遠不被繼承,此時就可以用 final 修飾。
  • 一個類不能同時被聲明爲 abstract 抽象類的和 final 的類。

注意:
final 類中所有的成員方法都會隱式的定義爲 final 方法。

1.2 final 修飾方法

final 方法意味着“最後的、最終的”含義,即被聲明 final 的方法只能使用,不能重載。

使用 final 方法的原因主要有兩個:

  • 把方法鎖定,以防止繼承類對其進行更改。
  • 效率,在早期的java版本中,會將 final 方法轉爲內嵌調用。但若方法過於龐大,可能在性能上不會有多大提升。因此在最近版本中,不需要 final 方法進行這些優化了。

demo 示例:

class A{
    private final void getName(){
        System.out.println("A.getName()...");
    }
}
class B extends A{
    public void getName(){
        System.out.println("B.getName()...");
    }

    public static void main(String[]args){
        B b = new B();
        b.getName();
    }
}
  • 結果:
B.getName()...

1.3 final 修飾變量

final 成員變量表示常量,只能被賦值一次,賦值後其值不再改變。

final 修飾成員變量時,必須要顯示初始化。這裏有兩種初始化方式:一種是在變量聲明的時候初始化;第二種方法是在這個變量所在的類的所有的構造函數中對這個變量賦初值。

如果將變量或者方法聲明爲 final,可以保證它們在使用中不被改變。在併發編程中,將公共變量設置爲 final 是最簡單的併發安全實現方法。

2 finally 用法

finally 是對 Java 異常處理模型的最佳補充。finally 結構使代碼總會執行,而不管有無異常發生。

常使用 finally關閉數據庫連接、關閉流等釋放資源的操作。防止程序發生異常退出而沒有釋放相應的資源。

2.1 finally 語句塊執行時機

  • 代碼示例:
@Test
public void testFinally1() {
    System.out.println("結果1:"+a1(null));
    System.out.println("-------------");
    System.out.println("結果2:"+a1(5));
    System.out.println("-------------");
    System.out.println("結果3:"+a1(3));
}

public static int a1(Integer aaa) {
    try {
        if (aaa.equals(5)) {
            System.out.println("55555");
            return 5;
        }
        System.out.println("11111");
        return 1;
    }catch (Exception e) {
        System.out.println("22222");
        return 2;
    }finally {
        System.out.println("33333");
        return 3;
    }
}
  • 輸出結果:
22222
33333
結果1:3
-------------
55555
33333
結果2:3
-------------
11111
33333
結果3:3
  • 結論:
    從運行結果來看,每次 return 的結果都是3(即finally語句),彷彿其他return語句被屏蔽掉了。

    事實也確實如此,因爲 finally 用法特殊,所以會撤銷之前的 return 語句,繼續執行最後的 finally 塊中的代碼。

2.2 finally 不執行的情況

  • 代碼示例:
@Test
public void test2() {
    System.out.println(a2(1));
    System.out.println("-------------");
    System.out.println(a2(9));
    System.out.println("-------------");
    System.out.println(a2(6));
}

public static int a2(Integer i) {
    System.out.println("start...");
    if (i == 1) {return 0;}
    System.out.println("before try block");
    try {
        System.out.println("try block");
        if (i == 6) {
            System.exit(0);
        }
        return i;
    }finally {
        System.out.println("finally block");
    }
}
  • 輸出結果:
start...
0
-------------
start...
before try block
try block
finally block
9
-------------
start...
before try block
try block
  • 結論:
  1. try 語句塊中調用 System.exit(0) 方法時,虛擬機會退出,中斷程序,finally 語句塊不會執行。
  2. 只有 try 語句塊執行了,且程序未中斷,finally 語句塊纔會執行。

3 finalize 用法

finalize() 是在 java.lang.Object 裏定義的,也就是說每一個對象都有這麼個方法。

這個方法在 gc 啓動,該對象被回收的時候被調用。其實 gc 可以回收大部分的對象(凡是 new 出來的對象,gc 都能搞定,一般情況下我們又不會用 new 以外的方式去創建對象),所以一般是不需要程序員去實現 finalize 的。

一個對象的 finalize() 方法只會被調用一次,而且 finalize() 被調用不意味着 gc 會立即回收該對象,所以有可能調用 finalize() 後,該對象又不需要被回收了,然後到了真正要被回收的時候,因爲前面調用過一次,所以不會調用 finalize(),產生問題。

所以,推薦不要使用 finalize() 方法,它跟析構函數不一樣。

代碼示例:

class C {
    public static void main(String[] args) {
        new C();
        System.gc();
    }

    protected void finalize() throws Throwable {
        System.out.println("finalize execute ... ");
    }
}

輸出結果:
finalize execute …

PS:如有疑問,歡迎指正。如果覺得不錯,點贊支持一下。
------ 更多內容歡迎關注 ----------
更多內容歡迎關注

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章