1. 程式人生 > >為什麼Java中的字串被定義為不可變的

為什麼Java中的字串被定義為不可變的

字串,想必大家最熟悉不過了,通常我們在程式碼中有幾種方式可以建立字串,比如:

String s = “Hollis”;

這時,其實會在堆記憶體中建立一個字串物件,其中儲存了一個字元陣列,該陣列中儲存了字串的內容。
這裡寫圖片描述
上面的箭頭可以理解為“儲存他的引用”。

當我們在程式碼中連續建立兩個相同的字串的時候,其實會指向同一個物件。因為當一個字串被被建立的時候,首先會去這個字串池中查詢,如果找到,直接返回對該字串的引用。
這裡寫圖片描述
這裡寫圖片描述
但是,如果在程式中明確宣告要新建立一個字串的話是可以在堆上重新建立一個物件的。如String s = new String(“Hollis”)
這裡寫圖片描述


這裡寫圖片描述
接著,我們來看兩個字串中常用的操作:擷取和連線會發生什麼,是在原來的字串物件上修改還是重新建立字串呢?

字串的連線。如String s1 = s.concat(“Chuang”);
這裡寫圖片描述
字串的擷取。如String s1 = s.substring(0,2);
這裡寫圖片描述
從上圖中我們可以得到一個結論,那就是——字串是不可變的,無論發生什麼操作,一個已經建立好的字串的內容不會被改變,對它的任何類似修改的操作其實都是新生成了一個字串物件。

那麼,為什麼要定義出不可變物件呢?

快取Hashcode
Java中經常會用到字串的雜湊碼(hashcode)。例如,在HashMap中,字串的不可變能保證其hashcode永遠保持一致,這樣就可以避免一些不必要的麻煩。這也就意味著每次在使用一個字串的hashcode的時候不用重新計算一次,這樣更加高效。

在String類中,有以下程式碼:

private int hash;

以上程式碼中hash變數中就儲存了一個String物件的hashcode,因為String類不可變,所以一旦物件被建立,該hash值也無法改變。所以,每次想要使用該物件的hashcode的時候,直接返回即可。

使其他類的使用更加便利
在介紹這個內容之前,先看以下程式碼:
這裡寫圖片描述
在上面的例子中,如果字串可以被改變,那麼以上用法將有可能違反Set的設計原則,因為Set要求其中的元素不可以重複。上面的程式碼只是為了簡單說明該問題,其實String類中並沒有value這個欄位值。

安全性
String被廣泛的使用在其他Java類中充當引數。比如網路連線、開啟檔案等操作。如果字串可變,那麼類似操作可能導致安全問題。因為某個方法在呼叫連線操作的時候,他認為會連線到某臺機器,但是實際上並沒有(其他引用同一String物件的值修改會導致該連線中的字串內容被修改)。可變的字串也可能導致反射的安全問題,因為他的引數也是字串。
這裡寫圖片描述

不可變物件天生就是執行緒安全的
因為不可變物件不能被改變,所以他們可以自由地在多個執行緒之間共享。不需要任何同步處理。

總之,String被設計成不可變的主要目的是為了安全和高效。所以,使String是一個不可變類是一個很好的設計。