修飾類
final 修飾類的時候代表這個類是不可以被擴展繼承的,例如 JDK 裏面的 String 類。
修飾方法
final 修飾方法的時候代表這個方法不能被子類重寫。
修飾變量
final 修飾變量的時候,這個變量一旦被賦值就不能再次被賦值。
緩存
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 類成爲名副其實的不可變安全類。
以上即爲昨天的問題的答案,小夥伴們對這個答案是否滿意呢?歡迎留言和我討論。
又要到年末了,你是不是又悄咪咪的開始看機會啦。爲了廣大小夥伴能充足電量,能順利通過 BAT 的面試官無情三連炮,我特意推出大型刷題節目。每天一道題目,第二天給答案,前一天給小夥伴們獨立思考的機會。