原文出處: Hollis(@Hollis_Chuang) String是Java中一個不可變的類,所以他一旦被實例化就無法被修改。不可變類的實例一旦創建,其成員變數的值就不能被修改。不可變類有很多優勢。本文總結了為什麼字元串被設計成不可變的。將涉及到記憶體、同步和數據結構相關的知識。 字元串池 字元串
原文出處: Hollis(@Hollis_Chuang)
String
是Java中一個不可變的類,所以他一旦被實例化就無法被修改。不可變類的實例一旦創建,其成員變數的值就不能被修改。不可變類有很多優勢。本文總結了為什麼字元串被設計成不可變的。將涉及到記憶體、同步和數據結構相關的知識。
字元串池
字元串池是方法區中的一部分特殊存儲。當一個字元串被被創建的時候,首先會去這個字元串池中查找,如果找到,直接返回對該字元串的引用。
下麵的代碼只會在堆中創建一個字元串
1 2 |
String string1 = "abcd" ;
String string2 = "abcd" ;
|
下麵是圖示:
如果字元串可變的話,當兩個引用指向指向同一個字元串時,對其中一個做修改就會影響另外一個。(請記住該影響,有助於理解後面的內容)
緩存Hashcode
Java中經常會用到字元串的哈希碼(hashcode)。例如,在HashMap中,字元串的不可變能保證其hashcode永遠保持一致,這樣就可以避免一些不必要的麻煩。這也就意味著每次在使用一個字元串的hashcode的時候不用重新計算一次,這樣更加高效。
在String類中,有以下代碼:
1 |
private int hash; //this is used to cache hash code.
|
以上代碼中
hash
變數中就保存了一個String對象的hashcode,因為String類不可變,所以一旦對象被創建,該hash值也無法改變。所以,每次想要使用該對象的hashcode的時候,直接返回即可。
使其他類的使用更加便利
在介紹這個內容之前,先看以下代碼:
1 2 3 4 5 6 7 |
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對象的值修改會導致該連接中的字元串內容被修改)。可變的字元串也可能導致反射的安全問題,因為他的參數也是字元串。
代碼示例:
1 2 3 4 5 6 7 |
boolean connect(string s){
if (!isSecure(s)) {
throw new SecurityException();
}
//如果s在該操作之前被其他的引用所改變,那麼就可能導致問題。
causeProblem(s);
}
|
不可變對象天生就是線程安全的
因為不可變對象不能被改變,所以他們可以自由地在多個線程之間共用。不需要任何同步處理。
總之,String
被設計成不可變的主要目的是為了安全和高效。所以,使String
是一個不可變類是一個很好的設計。
問啊-定製化IT教育平臺,牛人一對一服務,有問必答,開發編程社交頭條 官方網站:www.wenaaa.com 下載問啊APP,參與官方懸賞,賺百元現金。
QQ群290551701 聚集很多互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志於從事IT行業人員進入!