關於這個問題,網上有人說,是因為String類被寫成final或者String中的成員變數value陣列被寫成final,但其實並不是,下面做一個實驗
public final class MyString {
public final char[] value = {'z'};
}
首先我們定義了一個類Mystring,並且類和成員變數都被設定成final
public class Main {
public static void main(String[] args) {
MyString myString = new MyString();
System.out.println(myString.value);
myString.value[0] = 'a';
System.out.println(myString.value);
myString.value[0] = 'b';
System.out.println(myString.value);
}
}
執行結果
z
a
b
這說明僅僅把類和成員變數設定成final無法實現不可變,為了實現不可變我們還需要把這個成員變數設定成private不可見。
繼續我們的實驗
public final class MyString {
private final char[] value = {'z'};
}
這時再去執行上面的main函式,有如下結果,
E:\MIT6.830\Test_7\src\Main.java:12:36
java: value 在 MyString 中是 private 訪問控制
這時候我們無法直接修改value的值,但是這就可以了嗎?當然還沒有
為了保證string的不可變我們還要繼續做到以下幾點
- 首先設定內部成員變數的訪問修飾符為private,這樣就無法在類的外部直接訪問到這個成員變數
- 其次我們必須保證String類不提供成員方法去修改value,String的成員方法不是直接修改value而是透過新建一個String,並且把舊的string中的值複製到新的string物件中去。
- 在value上加final保證這個陣列的引用不會被修改而指向另一個陣列
- 在String上加final保證String沒有子類,因為子類可能提供方法去修改value,子類可以賦值給父類引用進而破壞String的不可變特性
儲存字串的陣列被 final 修飾且為私有的,並且String 類沒有提供/暴露修改這個字串的方法。
String 類被 final 修飾導致其不能被繼承,進而避免了子類破壞 String 不可變。