java final關鍵字的作用是什麼

2022-11-25 18:01:38

在java中,final可以用來修飾類、方法和變數。final修飾類,表示該類是無法被任何其他類繼承的,意味著此類在一個繼承樹中是一個葉子類,並且此類的設計已被認為很完美而不需要進行修改或擴充套件。final修飾類中的方法,表示該類是無法被任何其他類繼承的,不可以被重寫;也就是把該方法鎖定了,以防止繼承類對其進行更改。final修飾類中的變數,表示該變數一旦被初始化便不可改變。

程式設計師必備介面測試偵錯工具:

本教學操作環境:windows7系統、java8版、DELL G3電腦。

final關鍵字是什麼?

1、final可以用來修飾的結構:類、方法、變數

2、final用來修飾一個類:此類不能被其它類繼承。

當我們需要讓一個類永遠不被繼承,此時就可以用final修飾,但要注意:final類中所有的成員方法都會隱式的定義為final方法

比如:String類、System類、StringBuffer類

3、final 用來修飾方法 :表明此方法不可以被重寫

  • 作用

    (1) 把方法鎖定,以防止繼承類對其進行更改。

    (2) 效率,在早期的java版本中,會將final方法轉為內嵌呼叫。但若方法過於龐大,可能在效能上不會有多大提升。因此在最近版本中,不需要final方法進行這些優化了。

    final方法意味著「最後的、最終的」含義,即此方法不能被重寫。

  • 比如:Object類中的getClass( )

4、final 用來修飾變數 ,此時變數就相當於常數

  • final用來修飾屬性:可以考慮賦值的位置有:顯式初始化、程式碼塊中初始化、構造器中初始化

  • final修飾區域性變數:尤其是使用final修飾形參時,表明此形參是一個常數。當我們呼叫此方法時,給常數形參賦一個實參,一旦賦值之後,就只能在方法體內使用此形參的值,不能重新進行賦值。

  • 如果final修飾一個參照型別時,則在對其初始化之後便不能再讓其指向其他物件了或者說他的地址不能發生變化了(因為參照的值是一個地址,final要求值,即地址的值不發生變化),但該參照所指向的物件的內容是可以發生變化的。本質上是一回事。

5、使用 final 關鍵字宣告類、變數和方法需要注意以下幾點:

  • final 用在變數的前面表示變數的值不可以改變,此時該變數可以被稱為常數。

  • final 用在方法的前面表示方法不可以被重寫(子類中如果建立了一個與父類別中相同名稱、相同返回值型別、相同參數列的方法,只是方法體中的實現不同,以實現不同於父類別的功能,這種方式被稱為方法重寫,又稱為方法覆蓋。這裡瞭解即可,教學後面我們會詳細講解)。

  • final 用在類的前面表示該類不能有子類,即該類不可以被繼承。

final 修飾變數

final 修飾的變數即成為常數,只能賦值一次,但是 final 所修飾區域性變數和成員變數有所不同。

  • final 修飾的區域性變數必須使用之前被賦值一次才能使用。

  • final 修飾的成員變數在宣告時沒有賦值的叫「空白 final 變數」。空白 final 變數必須在構造方法或靜態程式碼塊中初始化。

注意:final 修飾的變數不能被賦值這種說法是錯誤的,嚴格的說法是,final 修飾的變數不可被改變,一旦獲得了初始值,該 final 變數的值就不能被重新賦值。

public class FinalDemo {
    void doSomething() {
        // 沒有在宣告的同時賦值
        final int e;
        // 只能賦值一次
        e = 100;
        System.out.print(e);
        // 宣告的同時賦值
        final int f = 200;
    }
    // 範例常數
    final int a = 5; // 直接賦值
    final int b; // 空白final變數
    // 靜態常數
    final static int c = 12;// 直接賦值
    final static int d; // 空白final變數
    // 靜態程式碼塊
    static {
        // 初始化靜態變數
        d = 32;
    }
    // 構造方法
    FinalDemo() {
        // 初始化範例變數
        b = 3;
        // 第二次賦值,會發生編譯錯誤
        // b = 4;
    }
}
登入後複製

上述程式碼第 4 行和第 6 行是宣告區域性常數,其中第 4 行只是宣告沒有賦值,但必須在使用之前賦值(見程式碼第 6 行),其實區域性常數最好在宣告的同時初始化。程式碼第 13、14、16 和 17 行都宣告成員常數。程式碼第 13 和 14 行是範例常數,如果是空白 final 變數(見程式碼第 14 行),則需要在構造方法中初始化(見程式碼第 27 行)。程式碼第 16 和 17 行是靜態常數,如果是空白 final 變數(見程式碼第 17 行),則需要在靜態程式碼塊中初始化(見程式碼第 21 行)。

另外,無論是那種常數只能賦值一次,見程式碼第 29 行為 b 常數賦值,因為之前 b 已經賦值過一次,因此這裡會發生編譯錯誤。

final 修飾基本型別變數和參照型別變數的區別

當使用 final 修飾基本型別變數時,不能對基本型別變數重新賦值,因此基本型別變數不能被改變。 但對於參照型別變數而言,它儲存的僅僅是一個參照,final 只保證這個參照型別變數所參照的地址不會改變,即一直參照同一個物件,但這個物件完全可以發生改變。

下面程式示範了 final 修飾陣列和 Person 物件的情形。

import java.util.Arrays;
class Person {
    private int age;
    public Person() {
    }
    // 有引數的構造器
    public Person(int age) {
        this.age = age;
    }
    // 省略age的setter和getter方法
    // age 的 setter 和 getter 方法
}
public class FinalReferenceTest {
    public static void main(String[] args) {
        // final修飾陣列變數,iArr是一個參照變數
        final int[] iArr = { 5, 6, 12, 9 };
        System.out.println(Arrays.toString(iArr));
        // 對陣列元素進行排序,合法
        Arrays.sort(iArr);
        System.out.println(Arrays.toString(iArr));
        // 對陣列元素賦值,合法
        iArr[2] = -8;
        System.out.println(Arrays.toString(iArr));
        // 下面語句對iArr重新賦值,非法
        // iArr = null;
        // final修飾Person變數,p是一個參照變數
        final Person p = new Person(45);
        // 改變Person物件的age範例變數,合法
        p.setAge(23);
        System.out.println(p.getAge());
        // 下面語句對P重新賦值,非法
        // p = null;
    }
}
登入後複製

從上面程式中可以看出,使用 final 修飾的參照型別變數不能被重新賦值,但可以改變參照型別變數所參照物件的內容。例如上面 iArr 變數所參照的陣列物件,final 修飾後的 iArr 變數不能被重新賦值,但 iArr 所參照陣列的陣列元素可以被改變。與此類似的是,p 變數也使用了 final 修飾,表明 p 變數不能被重新賦值,但 p 變數所參照 Person 物件的成員變數的值可以被改變。

注意:在使用 final 宣告變數時,要求全部的字母大寫,如 SEX,這點在開發中是非常重要的。

如果一個程式中的變數使用 public static final 宣告,則此變數將稱為全域性變數,如下面的程式碼:

public static final String SEX= "女";
登入後複製

final修飾方法

final 修飾的方法不可被重寫,如果出於某些原因,不希望子類重寫父類別的某個方法,則可以使用 final 修飾該方法。

Java 提供的 Object 類裡就有一個 final 方法 getClass(),因為 Java 不希望任何類重寫這個方法,所以使用 final 把這個方法密封起來。但對於該類提供的 toString() 和 equals() 方法,都允許子類重寫,因此沒有使用 final 修飾它們。

下面程式試圖重寫 final 方法,將會引發編譯錯誤。

public class FinalMethodTest {
    public final void test() {
    }
}
class Sub extends FinalMethodTest {
    // 下面方法定義將出現編譯錯誤,不能重寫final方法
    public void test() {
    }
}
登入後複製

上面程式中父類別是 FinalMethodTest,該類裡定義的 test() 方法是一個 final 方法,如果其子類試圖重寫該方法,將會引發編譯錯誤。

對於一個 private 方法,因為它僅在當前類中可見,其子類無法存取該方法,所以子類無法重寫該方法——如果子類中定義一個與父類別 private 方法有相同方法名、相同形參列表、相同返回值型別的方法,也不是方法重寫,只是重新定義了一個新方法。因此,即使使用 final 修飾一個 private 存取許可權的方法,依然可以在其子類中定義與該方法具有相同方法名、相同形參列表、相同返回值型別的方法。

下面程式示範瞭如何在子類中「重寫」父類別的 private final 方法。

public class PrivateFinalMethodTest {
    private final void test() {
    }
}
class Sub extends PrivateFinalMethodTest {
    // 下面的方法定義不會出現問題
    public void test() {
    }
}
登入後複製

上面程式沒有任何問題,雖然子類和父類別同樣包含了同名的 void test() 方法,但子類並不是重寫父類別的方法,因此即使父類別的 void test() 方法使用了 final 修飾,子類中依然可以定義 void test() 方法。

final 修飾的方法僅僅是不能被重寫,並不是不能被過載,因此下面程式完全沒有問題。

public class FinalOverload {
    // final 修飾的方法只是不能被重寫,完全可以被過載
    public final void test(){}
    public final void test(String arg){}
}
登入後複製

final修飾類

final 修飾的類不能被繼承。當子類繼承父類別時,將可以存取到父類別內部資料,並可通過重寫父類別方法來改變父類別方法的實現細節,這可能導致一些不安全的因素。為了保證某個類不可被繼承,則可以使用 final 修飾這個類。

下面程式碼示範了 final 修飾的類不可被繼承。

final class SuperClass {
}
class SubClass extends SuperClass {    //編譯錯誤
}
登入後複製

因為 SuperClass 類是一個 final 類,而 SubClass 試圖繼承 SuperClass 類,這將會引起編譯錯誤。

final 修飾符使用總結

1. final 修飾類中的變數

表示該變數一旦被初始化便不可改變,這裡不可改變的意思對基本型別變數來說是其值不可變,而對物件參照型別變數來說其參照不可再變。其初始化可以在兩個地方:一是其定義處,也就是說在 final 變數定義時直接給其賦值;二是在構造方法中。這兩個地方只能選其一,要麼在定義時給值,要麼在構造方法中給值,不能同時既在定義時賦值,又在構造方法中賦予另外的值。

2. final 修飾類中的方法

說明這種方法提供的功能已經滿足當前要求,不需要進行擴充套件,並且也不允許任何從此類繼承的類來重寫這種方法,但是繼承仍然可以繼承這個方法,也就是說可以直接使用。在宣告類中,一個 final 方法只被實現一次。

3. final 修飾類

表示該類是無法被任何其他類繼承的,意味著此類在一個繼承樹中是一個葉子類,並且此類的設計已被認為很完美而不需要進行修改或擴充套件。

對於 final 類中的成員,可以定義其為 final,也可以不是 final。而對於方法,由於所屬類為 final 的關係,自然也就成了 final 型。也可以明確地給 final 類中的方法加上一個 final,這顯然沒有意義。

以上就是java final關鍵字的作用是什麼的詳細內容,更多請關注TW511.COM其它相關文章!