Java final詳解

fianl 關(guān)鍵字

在 java 中被 final 修飾的域通常指的是“這是無法改變的。不想做改變的可能出于兩種理由:設(shè)計(jì)或效率。

  • final 關(guān)鍵字一般使用的三種情況:數(shù)據(jù)、方法、類

final 數(shù)據(jù)

許多編程語言都有某種方法來向編譯器告知這一塊數(shù)據(jù)時(shí)恒定不變的,比如:

一個(gè)永不改變的編譯時(shí)常量
一個(gè)在運(yùn)行時(shí)被初始化的值,而你并不喜歡它被改變

  • 在java 中常量必須是基本類型,并且以關(guān)鍵字 final 修飾,對(duì)常量進(jìn)行定義的時(shí)候必須進(jìn)行賦值。

  • 用于非基本類型對(duì)象引用時(shí),fianl 使其引用恒定不變。但是對(duì)象自身卻是可以修改的。

  • 一個(gè)既是 static 又是 final 的域只占據(jù)一段不能改變的儲(chǔ)存空間,一般用大寫的表示并用下劃線分隔各個(gè)單詞。

class Value{
    int i;
    public Value(int i) {
        this.i = i;
    }
}
public class Test {
    private static Random rand = new Random(47);
    private String id;
    public Test(String id) {
        this.id = id;
    }
    // 編譯時(shí)常數(shù)
    private final int valueOne = 11; 
    private static final int VALUE_TWO = 22; 
    public static final int VALUE_THREE = 33; //典型的 public 常量
    
    //不是編譯時(shí)的常數(shù),而是運(yùn)行時(shí)的常數(shù)
    private final int valueFour = rand.nextInt(20);
    private static final int VALUE_FIVE = rand.nextInt(20);

    private Value value1 = new Value(11);
    private final Value value2 = new Value(22); //定義一個(gè)final對(duì)象
    private static final Value VALUE_3 = new Value(33);
    
    @Override
    public String toString() {
        return id + " : " +"valueFour = " +valueFour +", VALUE_FIVE = " + VALUE_FIVE;
    }
    
    public static void main(String[] args) {
        Test test1 = new Test("test1");
        //test1.valueOne++; error 其值不能改變
         test1.value1 = new Value(9); 
         //test1.value2 = new Value(9); error final 使引用恒定不變
         test1.value2.i++; // 對(duì)象不是常量,對(duì)象其自身卻是可以修改的
         
         Test test2 = new Test("test2");
         System.out.println(test1);
         System.out.println(test2);
    }    
}

輸出為

test1 : valueFour = 15, VALUE_FIVE = 18
test2 : valueFour = 13, VALUE_FIVE = 18

  • 由于 valueOne 和 VALUE_TWO 都是帶有編譯數(shù)值的 final 基本類型,所有他們二者可以用做編譯期的常量,無重大區(qū)別。

  • VALUE_THREE 是一種更加電信的對(duì)常量進(jìn)行定義的方式:定義為 public,則可以用于包之外;定義為 static,則可以
    則強(qiáng)調(diào)只有一份;定義為 final,則說明是一個(gè)常量

  • 不能因?yàn)檎J(rèn)為某數(shù)據(jù)時(shí) fianl 的就認(rèn)為在編譯時(shí)可以知道其值。在上述代碼中的 valueFour 和 VALUE_FIVE 再運(yùn)行時(shí)使用隨機(jī)的值來初始化。

  • value1、value2、VALUE_3 展示了 final 引用的意義。在 main() 方法中可以看到,不能因?yàn)?value2 是 final 的,就認(rèn)為無法改變其值。

  • main() 方法最后展示了將 final 數(shù)值定義為靜態(tài)和和非靜態(tài)的區(qū)別。注意 VALUE_FIVE 兩次輸出的值是相同的,這是因?yàn)楸?static 修飾的,在類第一次裝載時(shí)已經(jīng)被初始化,而不是每次創(chuàng)建對(duì)象時(shí)都初始化。


空白final

Java 允許生成 空白final 即被聲明為 final 卻又未被給定初值的域(必須在構(gòu)造器中進(jìn)行初始化,不然編譯不通過),這樣我們?cè)谑褂蒙细`活,從而可以做到根據(jù)對(duì)象而有所不同。無論什么情況,編譯器都要確保 final 在使用前必須被初始化。

class A {
    private int i;
    public A(int i) {
        this.i = i ;
    }
}
class BlankFinal{
    private final int i = 0; //已初始化的final
    private final int j ; //空白final基本數(shù)據(jù)類型
    private final A a; //空白final引用
    
    public BlankFinal() {
        this.j =1; //初始化空白final基本數(shù)據(jù)類型
        this.a = new A(1); //初始化空白final引用
    }
    public BlankFinal(int j){
        this.j = j;
        this.a = new A(j);
    }
    public static void main(String[] args) {
        new BlankFinal();
        new BlankFinal(5);
    }
}


final參數(shù)

Java 允許在參數(shù)列表中以聲明的方式將參數(shù)指定為final,表示在方法中不能對(duì)參數(shù)引用進(jìn)行改變。

class B{
    public void say() {
        System.out.println("this class is B");
    }
}
class FinalArguments{
    void withFinal(final B b){
        //b = new B(); 不能對(duì)final修飾的引用參數(shù)進(jìn)行改變,編譯出錯(cuò)
    }
    void withOutFinal(B b){
        b = new B();// 這里就編譯就不會(huì)出錯(cuò)
        b.say();
    }
    int  f(final int i){
        //return i++; 不能對(duì)final修飾的基本數(shù)據(jù)類型參數(shù)進(jìn)行改變,編譯出錯(cuò)
        return i+1;
    }
    public static void main(String[] args) {
        FinalArguments fa = new FinalArguments();
        fa.withFinal(new B());
        fa.withOutFinal(new B());
        fa.f(5);
    }
}


final 方法

final 修飾方法一般用在防止子類去修改該方法。

  • 類中所有的 private 方法都隱式地指定為 final 的。由于子類無法取用 private 方法,所以也就無法對(duì)其進(jìn)行修改。可以為 private 方法聲明 final,但是毫無意義。

final 類

將某個(gè)類整體定義為 final 時(shí),表明當(dāng)前類不再被任何類繼承。出于安全性考慮,不希望該類有子類。

  • 無法繼承 fianl 類,但是可以使用組合的方式使用 final 類。
  • final 類禁止繼承,所以 fianl 類中所有的方法都被隱式指定為 final??梢栽?final 類的方法中添加 final,但是毫無意義。
final class C{
    public void say(){
        System.out.println("this is class c");
    }
}
//class Cc extends C{} 編譯出錯(cuò),fianl類不能被繼承 
class Cc{
    public static void main(String[] args) {
        C c = new C();
        c.say();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,835評(píng)論 18 399
  • 一、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對(duì)于byte類型而言...
    龍貓小爺閱讀 4,475評(píng)論 0 16
  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運(yùn)行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,822評(píng)論 0 11
  • 1.import static是Java 5增加的功能,就是將Import類中的靜態(tài)方法,可以作為本類的靜態(tài)方法來...
    XLsn0w閱讀 1,441評(píng)論 0 2
  • 昨天早上起得不算早,正式起床都五點(diǎn)半了,如果堅(jiān)持做完早課,洗漱、吃早飯,再乘地鐵去玉山公園,估計(jì)劉老師的課也差不多...
    如心1976閱讀 325評(píng)論 1 0

友情鏈接更多精彩內(nèi)容