final 這道送分題,你答對了嗎?

Photo By Instagram ro.junghwa

   

上期問題

你用過 Java 中的 final 關鍵字嗎?它有哪些作用?這也是出鏡率極高的題目哦。

我的答案

1. final 修飾類的時候代表這個類是不可以被擴展繼承的,例如 JDK 裏面的 String 類。

2. final 修飾方法的時候代表這個方法不能被子類重寫。

3. final 修飾變量的時候代表這個變量一旦被賦值就不能再次被賦值。

想必上面這三點是大家所熟知的,但是下面這 2 點你想到了嗎?


緩存

final 變量會被緩存在寄存器中而不需要去主從獲取,而非 final 變量的則需要去主存重新加載。

線程可見性

類的 final 域在編譯器層面會保證在類的構造器結束之前一定要初始化完成,同時 Java 內存模型會保證對象實例化後它的 final 域對其他線程是可見的,然而非 final 域並沒有這種待遇。例如如下代碼:

public class FinalFiled {
    final int x;
    int y;
    static FinalFiled f;


    public FinalFiled() {
        x = 100;
        y = 100;
    }


    static void writer() {
        f = new FinalFiled();
    }


    static void reader() {
        if (f != null) {
            int i = f.x;  // 保證此時一定是 100
            int j = f.y;  // 有可能此時還是 0
        }
    }
}

當線程 A 執行了 writer 方法後,有線程 B 會進入 f != null 成立條件的代碼塊,此時由於變量 x 是 final 修飾的,JMM 會保證 x 此時的值一定是 100,而 y 是非 final 的,則有可能此時 y 的值還是 0,並未被初始化。

安全性

String 類的安全性也得益於恰到好處的使用了大量的 final 域,大家可以去翻翻 String 類的源碼。我們來舉個例子,假設有線程 A 執行如下代碼段:

Global.flag = "/001/002".substring(4);

又有線程 B 執行如下代碼段:

String myS = Global.flag;
if (myS.equals("/001"))System.out.println(myS);

如果沒有 final 域的可見性保證,那麼線程 B 在執行的時候有可能看到的字符串的長度可能仍然是 0。當有了 final 域的可見性保證,就可以讓併發程序正確的執行。也使得 String 類成爲名副其實不可變安全類。

最後插播一個問題,今天有位讀者私信毛毛蟲說,可不可以把背景圖換成和文章內容相關的圖?不知道其他朋友們有沒有類似的想法?

毛毛蟲自己的想法有 2 點,第 1 點是覺得美美圖好看,文章過來就很想多看幾眼,嘿嘿;第 2 點是其實咱們都是技術文章,每篇都找和內容相關的背景圖還挺不好找的,當然啦如果大多數朋友都不喜歡看妹子圖,我們就去掉妹子圖啦。

歡迎的大家把自己的想法告訴毛毛蟲,讓毛毛蟲和朋友們的地盤變得更加美好。

以上即爲昨天的問題的答案,小夥伴們對這個答案是否滿意呢?歡迎留言和我討論。

又要到年末了,你是不是又悄咪咪的開始看機會啦。爲了廣大小夥伴能充足電量,能順利通過 BAT 的面試官無情三連炮,我特意推出大型刷題節目。每天一道題目,第二天給答案,前一天給小夥伴們獨立思考的機會。

點下“在看”,鼓勵一下?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章