為什么Java中的String類是不可變的?


String類是Java中的一個不可變類immutable class)。

簡單來說,不可變類就是實例在被創建之后不可修改。

《Effective Java》 Item 15 中提到了為了使類成為不可變,需要遵循的五條規則:

  1. 不要提供任何會修改對象狀態的方法。

  2. 保證類不會被擴展。

  3. 使所有的域都是final的。

  4. 使所有域都成為私有的。

  5. 確保對於任何可變組件的互斥訪問。

不可變類有許多優點,不可變類比可變類更加易於設計、實現和使用,不容易出錯,且更加安全。

下面來看一下Java把String類設計為不可變類的幾個原因:

1. 由於字符串池的存在

字符串池(String Pool)是方法區中的一塊存儲空間,當創建一個字符串時,如果池中已經存在相同的字符串就會返回其引用,而不是在堆中創建一個新對象。(此處指的是字面量創建字符串,用new關鍵字創建的話,無論池中存不存在都會在堆中創建一個新對象)

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

如果字符串是可變的話,通過一個引用改變它的值,將會導致其他引用的值也同樣改變,從而可能發生錯誤。

2. 緩存hashcode

Java中經常用到一個字符串的hashcode,如在HashMap和HashSet中。不可變性保證同一個字符串對象的hashcode總是相同的,而在使用時不用考慮其是否發生改變。

這意味着不需要每次都計算一遍hashcode,使程序更加高效。

/** Cache the hash code for the string */
private int hash; // Default to 0
3. 保證其他對象的使用

為了具體一點,舉一個栗子。

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";

 在這個例子中,如果String是可變的話將破壞HashSet(集合中可能會包含重復元素)。

4. 安全性

在Java中String被用作許多方法的參數,例如網絡連接,對文件的操作等等。

假如String不是不可變的,一個連接或文件將可能被改變,這會產生嚴重的安全隱患。

因為Java中反射的參數也是字符串,所以可變字符串同樣會產生安全問題。

下面是一個例子:

boolean connect(string s){
    if (!isSecure(s)) { 
throw new SecurityException(); 
}
    //here will cause problem, if s is changed before this by using other references.    
    causeProblem(s);
}
5. 不可變對象自然是線程安全的

不可變對象是線程安全的,它們可以被自由地共享,不要求同步。

 

不可變類的優勢有很多,當然也有缺點,就是對於每個不同的值都需要一個單獨的對象。


轉載請注明原文鏈接:http://www.cnblogs.com/justcooooode/p/7514863.html

 參考資料

《Effective Java》Item 15

https://www.programcreek.com/2013/04/why-string-is-immutable-in-java/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM