一、不可變類和不可變對象
Normally,you create an object and allow its contents to be changed later.However ,occasionally it is desirable to create an object whose contents cannot be changed once the object has been created.We call such an object as immutable object and its class as immutable class.
創建一個一旦其內容就不能在改變的對象,稱其為一個不可變對象(immutable object),而它的類稱為不可變類(immutable class)。
JDK中String的源碼
public final class String implements Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char[] value; /** Cache the hash code for the string */ private int hash;// Default to 0
可以看到String的本質是一個char數組,是對字符串數組的封裝,並且是被final修飾的,創建后不可改變。
二、String類不可變性的好處
1、便於實現字符串池(String pool)
在Java中,由於會大量的使用String常量,如果每一次聲明一個String都創建一個String對象,那將會造成極大的空間資源的浪費。Java提出了String pool的概念,在堆中開辟一塊存儲空間String pool,當初始化一個String變量時,如果該字符串已經存在了,就不會去創建一個新的字符串變量,而是會返回已經存在了的字符串的引用。
String a = "Hello world!";
String b = "Hello world!";
如果字符串是可變的,某一個字符串變量改變了其值,那么其指向的變量的值也會改變,String pool將不能夠實現!
2、使多線程安全
看下面這個場景,一個函數appendStr()在不可變的String參數后面加上一段“bbb”后返回。appendSb()負責在可變的StringBuilder后面加"bbb"。
public class test { // 不可變的String public static String appendStr(String s) { s += "bbb"; return s; } // 可變的StringBuilder public static StringBuilder appendSb(StringBuilder sb) { return sb.append("bbb"); } public static void main(String[] args) { String s = new String("aaa"); String ns = test.appendStr(s); System.out.println("String aaa>>>" + s.toString()); // StringBuilder做參數 StringBuilder sb = new StringBuilder("aaa"); StringBuilder nsb = test.appendSb(sb); System.out.println("StringBuilder aaa >>>" + sb.toString()); } }
如果程序員不小心像上面例子里,直接在傳進來的參數上加上“bbb”.因為Java對象參數傳的是引用,所有可變的StringBuffer參數就被改變了。可以看到變量sb在Test.appendSb(sb)操作之后,就變成了"aaabbb"。
有的時候這可能不是程序員的本意。所以String不可變的安全性就體現在這里。
在並發場景下,多個線程同時讀一個資源,是安全的,不會引發競爭,但對資源進行寫操作時是不安全的,不可變對象不能被寫,所以保證了多線程的安全。
The advantage of immutability comes with concurrency. It is difficult to maintain correctness in mutable objects, as multiple threads could be trying to change the state of the same object, leading to some threads seeing a different state of the same object, depending on the timing of the reads and writes to the said object.
By having an immutable object, one can ensure that all threads that are looking at the object will be seeing the same state, as the state of an immutable object will not change.
3、避免安全問題
在網絡連接和數據庫連接中字符串常常作為參數,例如,網絡連接地址URL,文件路徑path,反射機制所需要的String參數。其不可變性可以保證連接的安全性。如果字符串是可變的,黑客就有可能改變字符串指向對象的值,那么會引起很嚴重的安全問題。
因為String是不可變的,所以它的值是不可改變的。但由於String不可變,也就沒有任何方式能修改字符串的值,每一次修改都將產生新的字符串,如果使用char[]來保存密碼,仍然能夠將其中所有的元素設置為空和清零,也不會被放入字符串緩存池中,用字符串數組來保存密碼會更好。
4、加快字符串處理速度
由於String是不可變的,保證了hashcode的唯一性,於是在創建對象時其hashcode就可以放心的緩存了,不需要重新計算。這也就是Map喜歡將String作為Key的原因,處理速度要快過其它的鍵對象。所以HashMap中的鍵往往都使用String。
在String類的定義中有如下代碼:
private int hash;//用來緩存HashCode
總體來說,String不可變的原因要包括 設計考慮,效率優化,以及安全性這三大方面。
https://blog.csdn.net/jiahao1186/article/details/81150912
https://blog.csdn.net/u012546526/article/details/44458185
https://blog.csdn.net/hyddhy/article/details/87105691
https://www.cnblogs.com/wcyBlog/p/4073725.html、