Java final關鍵字及其內(nèi)存語義

final是Java中的一個關鍵字作岖,final可用于修飾類嵌器、方法枝笨、參數(shù)和變量(包括實例變量和類變量)沦寂。

final修飾類

final修飾的類具有不可繼承性学密,也就是如果一個類是final類型的,則這個類不允許有子類传藏。首先我們頂一個final類:

public final class FinalClass {
    private int field;
}

然后如果我們嘗試去繼承這個類的話編譯器會報錯:

public class FalseExtension extends FinalClass {

}
不允許繼承final類

編譯器提示我們:cannot extend final class腻暮,也就是說final類型的類不允許繼承。

final修飾方法

final修飾的方法具有不可變性漩氨,也就是說final的方法不允許在子類中被覆寫(@Override)西壮。下面我們來看一個反例:

不允許繼承覆蓋final方法

在Base子類Extension中我們覆寫(Override)了子類中的final方法,編譯器提示錯誤:final方法不能被覆寫叫惊。

final修飾參數(shù)和變量

如果參數(shù)用final修飾款青,那么在方法中我們不能對這個final參數(shù)進行修改:

public void test(final int x) {
    // x++; // 這句是非法的,因為x是final的
}

final修飾的變量(包括實例變量和類變量)具有引用不可變性霍狰,例如:private final int x = 1抡草,這里變量x是final類型的,如果我們嘗試修改x:x = 2蔗坯,編譯器就會提示出錯康震。
同樣的對于包裝類,如果我們嘗試修改變量的指針宾濒,一樣會提示錯誤:

class Test {
    
    private int x;

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }
}

final Test test = new Test();
// test = new Test(); // 這個表達式是非法的腿短,因為test是final的
test.setX(2); // 這個表達式是合法的因為這個表達式?jīng)]有修改test的引用

注意這里包裝類的不可變性是指引用的不可變,如果我們不修改變量的引用绘梦,而是通過訪問變量所指向的包裝類的方法去修改包裝類的屬性橘忱,這個是合法的。

編譯器對final變量的優(yōu)化

請看下面的例子:


public class Test {
    public static void main(String[] args)  {
        String a = "helloworld1"; 
        final String b = "helloworld";
        String c = "helloworld";
        String d = b + 2; 
        String e = d + 2;
        System.out.println((a == d));
        System.out.println((a == e));
    }
}

輸出結果:

true
false

可以看到a和d是指向同一個地址卸奉,而a和e則是指向不同的地址钝诚。這里就可以看出final變量和普通變量的區(qū)別了。變量b是final類型的榄棵,編譯器知道b的引用不會改變凝颇,因此直接可以“算出來”d就是“helloworld2”潘拱,那么a和d都是指向"helloworld2"字面量的變量,自然a == d成立了拧略。編譯器知道一個字符串變量是final不可變的變量后芦岂,就可以直接進行替換了。對于編譯期間不能確定的final變量辑鲤,編譯器則不會進行替換盔腔,請看下面這個例子:

public class Test {
    public static void main(String[] args)  {
        String a = "helloworld2"; 
        final String b = getHelloWorld();
        String c = b + 2; 
        System.out.println((a == c));
 
    }
     
    public static String getHelloWorld() {
        return "helloworld";
    }
}

這段代碼的輸出結果為false。

因為編譯器無法在編譯期就能確定b為"helloworld"月褥,因此編譯器無法對b進行替換弛随,所以a和c是不等的。

final的內(nèi)存語義

final域的重排序規(guī)則

  1. 在構造函數(shù)內(nèi)對一個final域的寫入宁赤,與隨后把這個被構造對象的引用賦值給一個引用變量舀透,這兩個操作之間不能重排序。
  2. 初次讀一個包含final域的對象的引用决左,與隨后初次讀這個final域愕够,這兩個操作之間不能重排序。

寫final域的重排序規(guī)則

寫final域的重排序規(guī)則禁止把final域的寫重排序到構造函數(shù)之外佛猛。這個規(guī)則的實現(xiàn)包含下面2個方面:

  1. JMM禁止編譯器把final域的寫重排序到構造函數(shù)之外惑芭。
  2. 編譯器會在final域的寫之后,構造函數(shù)return之前继找,插入一個StoreStore屏障遂跟。這個屏障禁止處理器把final域的寫重排序到構造函數(shù)之外。寫final域的重排序規(guī)則可以確保:在對象引用為任意線程可見之前婴渡,對象的final域已經(jīng)被正確初始化過了幻锁,而普通域不具有這個保障。

讀final域的重排序規(guī)則

讀final域的重排序規(guī)則是边臼,在一個線程中哄尔,初次讀對象引用與初次讀該對象包含的final域,JMM禁止處理器重排序這兩個操作(注意柠并,這個規(guī)則僅僅針對處理器)岭接。編譯器會在讀final域操作的前面插入一個LoadLoad屏障。初次讀對象引用與初次讀該對象包含的final域臼予,這兩個操作之間存在間接依賴關系亿傅。由于編譯器遵守間接依賴關系,因此編譯器不會重排序這兩個操作瘟栖。大多數(shù)處理器也會遵守間接依賴,也不會重排序這兩個操作谅阿。但有少數(shù)處理器允許對存在間接依賴關系的操作做重排序(比如alpha處理器)半哟,這個規(guī)則就是專門用來針對這種處理器的酬滤。讀final域的重排序規(guī)則可以確保:在讀一個對象的final域之前,一定會先讀包含這個final域的對象的引用寓涨。

final域為引用類型

對于引用類型盯串,寫final域的重排序規(guī)則對編譯器和處理器增加了如下約束:在構造函數(shù)內(nèi)對一個final引用的對象的成員域的寫入,與隨后在構造函數(shù)外把這個被構造對象的引用賦值給一個引用變量戒良,這兩個操作之間不能重排序体捏。這一規(guī)則確保了其他線程能讀到被正確初始化的final引用對象的成員域。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糯崎,一起剝皮案震驚了整個濱河市几缭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌沃呢,老刑警劉巖年栓,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異薄霜,居然都是意外死亡某抓,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門惰瓜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來否副,“玉大人,你說我怎么就攤上這事崎坊”纲鳎” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵流强,是天一觀的道長痹届。 經(jīng)常有香客問我,道長打月,這世上最難降的妖魔是什么队腐? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮奏篙,結果婚禮上柴淘,老公的妹妹穿的比我還像新娘。我一直安慰自己秘通,他們只是感情好为严,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肺稀,像睡著了一般第股。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上话原,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天夕吻,我揣著相機與錄音诲锹,去河邊找鬼。 笑死涉馅,一個胖子當著我的面吹牛归园,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播稚矿,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼庸诱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了晤揣?” 一聲冷哼從身側響起桥爽,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎碉渡,沒想到半個月后聚谁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡滞诺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年形导,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片习霹。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡朵耕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出淋叶,到底是詐尸還是另有隱情阎曹,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布煞檩,位于F島的核電站处嫌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏斟湃。R本人自食惡果不足惜熏迹,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望凝赛。 院中可真熱鬧注暗,春花似錦、人聲如沸墓猎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毙沾。三九已至骗卜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背寇仓。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工勇皇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人焚刺。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像门烂,于是被迫代替她去往敵國和親乳愉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容