String類是Java中的一個不可變類(immutable class)。
簡單來說,不可變類就是實例在被創建之后不可修改。
在《Effective Java》 Item 15 中提到了為了使類成為不可變,需要遵循的五條規則:
-
不要提供任何會修改對象狀態的方法。
-
保證類不會被擴展。
-
使所有的域都是final的。
-
使所有域都成為私有的。
-
確保對於任何可變組件的互斥訪問。
不可變類有許多優點,不可變類比可變類更加易於設計、實現和使用,不容易出錯,且更加安全。
下面來看一下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/