教妹學(xué)Java第23講: final 關(guān)鍵字

“哥,昨天我們學(xué)校封校了,因為要考研。今天終于可以回來跟著你學(xué) Java 了,好期待?。 比盟坪跻呀?jīng)迫不及待了,拉了個椅子就在電腦前面做下了。
“哥,今天學(xué)什么呢?”
“今天學(xué)一個重要的關(guān)鍵字——final。”我面帶著樸實無華的微笑回答著她,“對了,三妹,你打算考研嗎?”
“還沒想過,我今年才大一呢,到時候再說吧,你決定。”
“好吧?!蔽覕倲偸郑硎竞軣o辜,真的是所有的決定都交給我這個哥哥了,如果決定錯了,鍋得背上。
01、final 變量
“好了,我們先來看 final 修飾的變量吧!”
“被 final 修飾的變量無法重新賦值。換句話說,final 變量一旦初始化,就無法更改?!?/p>
“來看這行代碼?!?/p>
final?int?age?=?18;
“當(dāng)嘗試將 age 的值修改為 30 的時候,編譯器就生氣了?!?/p>
“再來看這段代碼?!?/p>
public?class?Pig?{
???private?String?name;
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
}
“這是一個很普通的 Java 類,它有一個字段 name?!?/p>
“然后,我們創(chuàng)建一個測試類,并聲明一個 final 修飾的 Pig 對象。”
final?Pig?pig?=?new?Pig();
“如果嘗試將 pig 重新賦值的話,編譯器同樣會生氣?!?/p>
“但我們?nèi)匀豢梢匀バ薷?pig 對象的 name?!?/p>
final?Pig?pig?=?new?Pig();
pig.setName("特立獨行");
System.out.println(pig.getName());?//?特立獨行
“另外,final 修飾的成員變量必須有一個默認值,否則編譯器將會提醒沒有初始化?!?/p>
“final 和 static 一起修飾的成員變量叫做常量,常量名必須全部大寫?!?/p>
public?class?Pig?{
???private?final?int?age?=?1;
???public?static?final?double?PRICE?=?36.5;
}
“有時候,我們還會用 final 關(guān)鍵字來修飾參數(shù),它意味著參數(shù)在方法體內(nèi)不能被再修改?!?/p>
“來看下面這段代碼?!?/p>
public?class?ArgFinalTest?{
????public?void?arg(final?int?age)?{
????}
????public?void?arg1(final?String?name)?{
????}
}
“如果嘗試去修改它的話,編譯器會提示以下錯誤?!?/p>
02、final 方法
“被 final 修飾的方法不能被重寫。如果我們在設(shè)計一個類的時候,認為某些方法不應(yīng)該被重寫,就應(yīng)該把它設(shè)計成 final 的。”
“Thread 類就是一個例子,它本身不是 final 的,這意味著我們可以擴展它,但它的 isAlive() 方法是 final 的。”
public?class?Thread?implements?Runnable?{
????public?final?native?boolean?isAlive();
}
“需要注意的是,該方法是一個本地(native)方法,用于確認線程是否處于活躍狀態(tài)。而本地方法是由操作系統(tǒng)決定的,因此重寫該方法并不容易實現(xiàn)?!?/p>
“來看這段代碼。”
public?class?Actor?{
????public?final?void?show()?{
????}
}
“當(dāng)我們想要重寫該方法的話,就會出現(xiàn)編譯錯誤?!?/p>
“如果一個類中的某些方法要被其他方法調(diào)用,則應(yīng)考慮事被調(diào)用的方法稱為 final 方法,否則,重寫該方法會影響到調(diào)用方法的使用。”
“三妹,來問你一個問題吧?!闭氤萌没卮饐栴}的時候喝口水。
“你說吧,哥?!?/p>
“一個類是 final 的,和一個類不是 final,但它所有的方法都是 final 的,考慮一下,它們之間有什么區(qū)別?”
“我能想到的一點,就是前者不能被繼承,也就是說方法無法被重寫;后者呢,可以被繼承,然后追加一些非 final 的方法?!边€沒等我把水咽下去,三妹就回答好了,著實驚呆了我。
“嗯嗯嗯,沒毛病沒毛病,進步很大?。 ?/p>
“那必須啊,誰叫我是你妹呢?!?/p>
03、final 類
“如果一個類使用了 final 關(guān)鍵字修飾,那么它就無法被繼承.....”
“等等,哥,我知道,String 類就是一個 final 類。”還沒等我說完,三妹就搶著說到。
“說得沒毛病?!?/p>
public?final?class?String
????implements?java.io.Serializable,?Comparable<String>,?CharSequence,
???????????????Constable,?ConstantDesc?{}
“那三妹你知道為什么 String 類要設(shè)計成 final 嗎?”
“這個還真不知道?!比玫谋砬橥嘎冻鲞@種無奈。
“原因大致有 3 個。”
為了實現(xiàn)字符串常量池 為了線程安全 為了 HashCode 的不可變性
“想了解更詳細的原因,可以一會看看我之前寫的這篇文章?!?/p>
“任何嘗試從 final 類繼承的行為將會引發(fā)編譯錯誤。來看這段代碼。”
public?final?class?Writer?{
????private?String?name;
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
}
“嘗試去繼承它,編譯器會提示以下錯誤,Writer 類是 final 的,無法繼承?!?/p>
“不過,類是 final 的,并不意味著該類的對象是不可變的?!?/p>
“來看這段代碼?!?/p>
Writer?writer?=?new?Writer();
writer.setName("沉默王二");
System.out.println(writer.getName());?//?沉默王二
“Writer 的 name 字段的默認值是 null,但可以通過 settter 方法將其更改為沉默王二。也就是說,如果一個類只是 final 的,那么它并不是不可變的全部條件?!?/p>
“關(guān)于不可變類,我之前也單獨講過一篇,你一會去看看。”
“把一個類設(shè)計成 final 的,有其安全方面的考慮,但不應(yīng)該故意為之,因為把一個類定義成 final 的,意味著它沒辦法繼承,假如這個類的一些方法存在一些問題的話,我們就無法通過重寫的方式去修復(fù)它?!?/p>
“三妹,final 關(guān)鍵字我們就學(xué)到這里吧,你一會再學(xué)習(xí)一下 Java 字符串為什么是不可變的和不可變類?!蔽胰嘁蝗喾咐У碾p眼,疲憊地給三妹說,“學(xué)完這兩個知識點,你會對 final 的認知更清晰一些?!?/p>
“好的,二哥,我這就去學(xué)習(xí)去。你去休息會?!?/p>
我起身站到陽臺上,看著窗外的車水馬龍,不一會兒,就發(fā)起來呆。
“好想去再看一場周杰倫的演唱會,不知道 2021 有沒有這個機會?!?/p>
我心里這樣想著,天漸漸地暗了下來。
