淺析Java中的final關(guān)鍵字

談到final關(guān)鍵字,想必很多人都不陌生腌紧,在使用匿名內(nèi)部類的時(shí)候可能會(huì)經(jīng)常用到final關(guān)鍵字砸喻。另外,Java中的String類就是一個(gè)final類挟裂,那么今天我們就來了解final這個(gè)關(guān)鍵字的用法享钞。下面是本文的目錄大綱:

一.final關(guān)鍵字的基本用法

二.深入理解final關(guān)鍵字

若有不正之處,請(qǐng)多多諒解并歡迎指正诀蓉。

請(qǐng)尊重作者勞動(dòng)成果栗竖,轉(zhuǎn)載請(qǐng)標(biāo)明原文鏈接:

http://www.cnblogs.com/dolphin0520/p/3736238.html

一.final關(guān)鍵字的基本用法

在Java中暑脆,final關(guān)鍵字可以用來修飾類、方法和變量(包括成員變量和局部變量)狐肢。下面就從這三個(gè)方面來了解一下final關(guān)鍵字的基本用法添吗。

1.修飾類

當(dāng)用final修飾一個(gè)類時(shí),表明這個(gè)類不能被繼承处坪。也就是說根资,如果一個(gè)類你永遠(yuǎn)不會(huì)讓他被繼承,就可以用final進(jìn)行修飾同窘。final類中的成員變量可以根據(jù)需要設(shè)為final玄帕,但是要注意final類中的所有成員方法都會(huì)被隱式地指定為final方法。

image

在使用final修飾類的時(shí)候想邦,要注意謹(jǐn)慎選擇裤纹,除非這個(gè)類真的在以后不會(huì)用來繼承或者出于安全的考慮,盡量不要將類設(shè)計(jì)為final類丧没。

2.修飾方法

下面這段話摘自《Java編程思想》第四版第143頁:

“使用final方法的原因有兩個(gè)鹰椒。第一個(gè)原因是把方法鎖定,以防任何繼承類修改它的含義呕童;第二個(gè)原因是效率漆际。在早期的Java實(shí)現(xiàn)版本中盗胀,會(huì)將final方法轉(zhuǎn)為內(nèi)嵌調(diào)用陌僵。但是如果方法過于龐大荤堪,可能看不到內(nèi)嵌調(diào)用帶來的任何性能提升良价。在最近的Java版本中,不需要使用final方法進(jìn)行這些優(yōu)化了柠座∑穑“

因此省有,如果只有在想明確禁止 該方法在子類中被覆蓋的情況下才將方法設(shè)置為final的浩销。

注:類的private方法會(huì)隱式地被指定為final方法贯涎。

3.修飾變量

修飾變量是final用得最多的地方,也是本文接下來要重點(diǎn)闡述的內(nèi)容慢洋。首先了解一下final變量的基本語法:

對(duì)于一個(gè)final變量塘雳,如果是基本數(shù)據(jù)類型的變量,則其數(shù)值一旦在初始化之后便不能更改普筹;如果是引用類型的變量粉捻,則在對(duì)其初始化之后便不能再讓其指向另一個(gè)對(duì)象。

舉個(gè)例子:

image

上面的一段代碼中斑芜,對(duì)變量i和obj的重新賦值都報(bào)錯(cuò)了。

二.深入理解final關(guān)鍵字

在了解了final關(guān)鍵字的基本用法之后祟霍,這一節(jié)我們來看一下final關(guān)鍵字容易混淆的地方杏头。

1.類的final變量和普通變量有什么區(qū)別盈包?

當(dāng)用final作用于類的成員變量時(shí),成員變量(注意是類的成員變量醇王,局部變量只需要保證在使用之前被初始化賦值即可)必須在定義時(shí)或者構(gòu)造器中進(jìn)行初始化賦值呢燥,而且final變量一旦被初始化賦值之后,就不能再被賦值了寓娩。

那么final變量和普通變量到底有何區(qū)別呢叛氨?下面請(qǐng)看一個(gè)例子:

|

|

public class Test {

public static void main(String[] args) {

String a = ``"hello2"``;

final String b = ``"hello"``;

String d = ``"hello"``;

String c = b + ``2``;

String e = d + ``2``;

System.out.println((a == c));

System.out.println((a == e));

}

}

|

image

View Code

大家可以先想一下這道題的輸出結(jié)果。為什么第一個(gè)比較結(jié)果為true棘伴,而第二個(gè)比較結(jié)果為fasle寞埠。這里面就是final變量和普通變量的區(qū)別了,當(dāng)final變量是基本數(shù)據(jù)類型以及String類型時(shí)焊夸,如果在編譯期間能知道它的確切值仁连,則編譯器會(huì)把它當(dāng)做編譯期常量使用。也就是說在用到該final變量的地方阱穗,相當(dāng)于直接訪問的這個(gè)常量饭冬,不需要在運(yùn)行時(shí)確定。這種和C語言中的宏替換有點(diǎn)像揪阶。因此在上面的一段代碼中昌抠,由于變量b被final修飾,因此會(huì)被當(dāng)做編譯器常量鲁僚,所以在使用到b的地方會(huì)直接將變量b 替換為它的 值炊苫。而對(duì)于變量d的訪問卻需要在運(yùn)行時(shí)通過鏈接來進(jìn)行。想必其中的區(qū)別大家應(yīng)該明白了蕴茴,不過要注意劝评,只有在編譯期間能確切知道final變量值的情況下,編譯器才會(huì)進(jìn)行這樣的優(yōu)化倦淀,比如下面的這段代碼就不會(huì)進(jìn)行優(yōu)化:

|

|

public class Test {

public static void main(String[] args) {

String a = ``"hello2"``;

final String b = getHello();

String c = b + ``2``;

System.out.println((a == c));

}

public static String getHello() {

return "hello"``;

}

}

|

這段代碼的輸出結(jié)果為false蒋畜。

2.被final修飾的引用變量指向的對(duì)象內(nèi)容可變嗎?

在上面提到被final修飾的引用變量一旦初始化賦值之后就不能再指向其他的對(duì)象撞叽,那么該引用變量指向的對(duì)象的內(nèi)容可變嗎姻成?看下面這個(gè)例子:

|

|

public class Test {

public static void main(String[] args) {

final MyClass myClass = ``new MyClass();

System.out.println(++myClass.i);

}

}

class MyClass {

public int i = ``0``;

}

|

這段代碼可以順利編譯通過并且有輸出結(jié)果,輸出結(jié)果為1愿棋。這說明引用變量被final修飾之后科展,雖然不能再指向其他對(duì)象,但是它指向的對(duì)象的內(nèi)容是可變的糠雨。

3.final和static

很多時(shí)候會(huì)容易把static和final關(guān)鍵字混淆才睹,static作用于成員變量用來表示只保存一份副本,而final的作用是用來保證變量不可變±湃粒看下面這個(gè)例子:

|

|

public class Test {

public static void main(String[] args) {

MyClass myClass1 = ``new MyClass();

MyClass myClass2 = ``new MyClass();

System.out.println(myClass1.i);

System.out.println(myClass1.j);

System.out.println(myClass2.i);

System.out.println(myClass2.j);

}

}

class MyClass {

public final double i = Math.random();

public static double j = Math.random();

}

|

運(yùn)行這段代碼就會(huì)發(fā)現(xiàn)垮庐,每次打印的兩個(gè)j值都是一樣的,而i的值卻是不同的坞琴。從這里就可以知道final和static變量的區(qū)別了哨查。

4.匿名內(nèi)部類中使用的外部局部變量為什么只能是final變量?

這個(gè)問題請(qǐng)參見上一篇博文中《Java內(nèi)部類詳解》中的解釋剧辐,在此處不再贅述寒亥。

5.關(guān)于final參數(shù)的問題

關(guān)于網(wǎng)上流傳的”當(dāng)你在方法中不需要改變作為參數(shù)的對(duì)象變量時(shí),明確使用final進(jìn)行聲明荧关,會(huì)防止你無意的修改而影響到調(diào)用方法外的變量“這句話溉奕,我個(gè)人理解這樣說是不恰當(dāng)?shù)摹?/p>

因?yàn)闊o論參數(shù)是基本數(shù)據(jù)類型的變量還是引用類型的變量,使用final聲明都不會(huì)達(dá)到上面所說的效果羞酗。

看這個(gè)例子就清楚了:

image

上面這段代碼好像讓人覺得用final修飾之后腐宋,就不能在方法中更改變量i的值了。殊不知檀轨,方法changeValue和main方法中的變量i根本就不是一個(gè)變量胸竞,因?yàn)閖ava參數(shù)傳遞采用的是值傳遞,對(duì)于基本類型的變量参萄,相當(dāng)于直接將變量進(jìn)行了拷貝卫枝。所以即使沒有final修飾的情況下,在方法內(nèi)部改變了變量i的值也不會(huì)影響方法外的i讹挎。

再看下面這段代碼:

|

public class Test {

public static void main(String[] args) {

MyClass myClass = ``new MyClass();

StringBuffer buffer = ``new StringBuffer(``"hello"``);

myClass.changeValue(buffer);

System.out.println(buffer.toString());

}

}

class MyClass {

void changeValue(``final StringBuffer buffer) {

buffer.append(``"world"``);

}

}

|

運(yùn)行這段代碼就會(huì)發(fā)現(xiàn)輸出結(jié)果為 helloworld校赤。很顯然,用final進(jìn)行修飾并沒有阻止在changeValue中改變buffer指向的對(duì)象的內(nèi)容筒溃。有人說假如把final去掉了马篮,萬一在changeValue中讓buffer指向了其他對(duì)象怎么辦。有這種想法的朋友可以自己動(dòng)手寫代碼試一下這樣的結(jié)果是什么怜奖,如果把final去掉了浑测,然后在changeValue中讓buffer指向了其他對(duì)象,也不會(huì)影響到main方法中的buffer歪玲,原因在于java采用的是值傳遞迁央,對(duì)于引用變量,傳遞的是引用的值滥崩,也就是說讓實(shí)參和形參同時(shí)指向了同一個(gè)對(duì)象岖圈,因此讓形參重新指向另一個(gè)對(duì)象對(duì)實(shí)參并沒有任何影響。

所以關(guān)于網(wǎng)上流傳的final參數(shù)的說法钙皮,我個(gè)人不是很贊同蜂科。

參考資料:

《Java編程思想》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末顽决,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子崇摄,更是在濱河造成了極大的恐慌擎值,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逐抑,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡屹蚊,警方通過查閱死者的電腦和手機(jī)厕氨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汹粤,“玉大人命斧,你說我怎么就攤上這事≈黾妫” “怎么了国葬?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)芹壕。 經(jīng)常有香客問我汇四,道長(zhǎng),這世上最難降的妖魔是什么踢涌? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任通孽,我火速辦了婚禮,結(jié)果婚禮上睁壁,老公的妹妹穿的比我還像新娘背苦。我一直安慰自己,他們只是感情好潘明,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布行剂。 她就那樣靜靜地躺著,像睡著了一般钳降。 火紅的嫁衣襯著肌膚如雪厚宰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天牲阁,我揣著相機(jī)與錄音固阁,去河邊找鬼。 笑死城菊,一個(gè)胖子當(dāng)著我的面吹牛备燃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播凌唬,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼并齐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼漏麦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起况褪,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤撕贞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后测垛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捏膨,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年食侮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了号涯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锯七,死狀恐怖链快,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情眉尸,我是刑警寧澤域蜗,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站噪猾,受9級(jí)特大地震影響霉祸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜畏妖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一脉执、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧戒劫,春花似錦半夷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至茵典,卻和暖如春湘换,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背统阿。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工彩倚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人扶平。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓帆离,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親结澄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哥谷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348