為什么Java中字符串是不可變的


前言

在Java中,字符串是一個不可變的類,一個不可變的類指的是它的實例對象不能被修改,所有關於這個對象的信息在這個對象被創建時已初始化且不能被改變。

不可變類有很多優勢,這篇文章總結了字符串類之所以被設計成不可變類的原因,涉及內存模型,線程同步,數據結構等知識。

字符串常量池的需求

字符串常量池是方法區中的一塊特別存儲區域。當需要創建一個字符串時,如果它的值在字符串常量池中已存在,那么常量池中的該字符串引用將被直接返回,而不會創建一個新的字符串對象返回其引用。

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

如果字符串是可變的,那么通過一個引用改變字符串的值,其它該字符串對象的引用將得到錯誤的值。

緩存Hashcode

字符串的hashcode在java中經常被使用,如HashMap。不可變保證了hashcode會一直相同,所以它可以緩存起來而不需要擔心改變。這也意味着,每次使用String的時候,不需要重新計算hashcode,這使得性能更加有效,所以我們經常會看到map的key使用字符串。

在String類中,有一個hash字段用於緩存hash code。

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

方便其它對象的使用

為了更加具體的說明,看下下面的程序:

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

在這個例子中,如果字符串是可變的,那么它的value會被改變,這將違背Set集合的設計(不允許重復元素)。當然,這僅僅是一個示例,實際情況,String是沒有value字段的。

安全性

字符串作為參數被廣泛使用,如網絡連接,文件打開操作等。如果字符串是可變的,那么網絡連接或者文件將會被改變,這將引起嚴重的安全威脅。某個方法被認為連接到某一台機器,但是卻被改變了,連接到其它機器。在反射中,可變的字符串同樣會引起安全問題,因為參數同樣是字符串。

如下代碼是一個例子:

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);
}

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

因為不可變對象不能被修改,它們可以被多線程共享,這消除了同步操作。

 

總的來說,字符串被設計成不可變是出於性能和安全考慮,這也是為什么通常不可變類比較受歡迎。

 

譯文鏈接:http://www.programcreek.com/2013/04/why-string-is-immutable-in-java/


免責聲明!

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



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