首頁 > Java > Java基礎 > java final關鍵字的作用是什麼

java final關鍵字的作用是什麼

青灯夜游
發布: 2022-11-25 16:26:26
原創
24600 人瀏覽過

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

java 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教學

以上是java final關鍵字的作用是什麼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板