Java字符串之String的不變性

定義一個字符串

String s = "abcd";

s中保存了string對象的引用。下面的箭頭能夠理解爲「存儲他的引用」。緩存

使用變量來賦值變量

String s2 = s;

s2保存了相同的引用值,由於他們表明同一個對象。安全

字符串鏈接

s = s.concat("ef");

s中保存的是一個從新建立出來的string對象的引用。網絡

總結

一旦一個string對象在內存(堆)中被建立出來,他就沒法被修改。特別要注意的是,String類的全部方法都沒有改變字符串自己的值,都是返回了一個新的對象。jvm

若是你須要一個可修改的字符串,應該使用StringBuffer 或者 StringBuilder。不然會有大量時間浪費在垃圾回收上,由於每次試圖修改都有新的string對象被建立出來。ui

 

留個問題:this

爲何Java要把字符串設計成不可變的?spa

 解答:線程

String是Java中一個不可變的類,因此他一旦被實例化就沒法被修改。不可變類的實例一旦建立,其成員變量的值就不能被修改。不可變類有不少優點。設計

字符串池

字符串池是方法區中的一部分特殊存儲。當一個字符串被被建立的時候,首先會去這個字符串池中查找,若是找到,直接返回對該字符串的引用。code

下面的代碼只會在堆中建立一個字符串

String string1 = "abcd";
String string2 = "abcd";

下面是圖示:

若是字符串可變的話,當兩個引用指向指向同一個字符串時,對其中一個作修改就會影響另一個。(請記住該影響,有助於理解後面的內容)

緩存Hashcode

Java中常常會用到字符串的哈希碼(hashcode)。例如,在HashMap中,字符串的不可變能保證其hashcode永遠保持一致,這樣就能夠避免一些沒必要要的麻煩。這也就意味着每次在使用一個字符串的hashcode的時候不用從新計算一次,這樣更加高效。

在String類中,有如下代碼:

private int hash;//this is used to cache hash code.

以上代碼中hash變量中就保存了一個String對象的hashcode,由於String類不可變,因此一旦對象被建立,該hash值也沒法改變。因此,每次想要使用該對象的hashcode的時候,直接返回便可。

使其餘類的使用更加便利

在介紹這個內容以前,先看如下代碼:

HashSet<String> set = new HashSet<String>();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));

for(String a: set)
    a.value = "a";

在上面的例子中,若是字符串能夠被改變,那麼以上用法將有可能違反Set的設計原則,由於Set要求其中的元素不能夠重複。上面的代碼只是爲了簡單說明該問題,其實String類中並無value這個字段值。

安全性

String被普遍的使用在其餘Java類中充當參數。好比網絡鏈接、打開文件等操做。若是字符串可變,那麼相似操做可能致使安全問題。由於某個方法在調用鏈接操做的時候,他認爲會鏈接到某臺機器,可是實際上並無(其餘引用同一String對象的值修改會致使該鏈接中的字符串內容被修改)。可變的字符串也可能致使反射的安全問題,由於他的參數也是字符串。

代碼示例:

boolean connect(string s){
    if (!isSecure(s)) { 
throw new SecurityException(); 
}
    //若是s在該操做以前被其餘的引用所改變,那麼就可能致使問題。   
    causeProblem(s);
}

不可變對象天生就是線程安全的

由於不可變對象不能被改變,因此他們能夠自由地在多個線程之間共享。不須要任何同步處理。

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

相關文章
相關標籤/搜索