-
1 # ramostear
-
2 # java架構設計
String類在Java中被設計成不可變的,這是Java開發人員大家都知道的事情。但是要讓大家真的說出來為什麼String在Java中是不可變的,有時候真的能讓人一時語塞,或者說的不夠全面。這個問題有各種提問的方式,例如:“為什麼Java中要把String類設計成不可變的?”,“String類被設計成不可變類有什麼好處?”基本上都是一個思路。
接下來個人從以下幾個方面來談談自己對這個問題的看法:
什麼是不可變?《Effective Java》中對於不可變類的解釋如下:
不可變類只是其例項不能被修改的類。每個例項中包含的所有資訊都必須在建立該例項的時候就提供,並且在物件的整個生命週期內固定不變。為了使類不可變,要遵循下面五條規則:
1. 不要提供任何會修改物件狀態的方法。
2. 保證類不會被擴充套件。 一般的做法是讓這個類稱為 的,防止子類化,破壞該類的不可變行為。
3. 使所有的域都是 final 的。
4. 使所有的域都成為私有的。 防止客戶端獲得訪問被域引用的可變物件的許可權,並防止客戶端直接修改這些物件。
5. 確保對於任何可變性元件的互斥訪問。 如果類具有指向可變物件的域,則必須確保該類的客戶端無法獲得指向這些物件的引用。
不可變帶來的好處多執行緒安全:不可變物件天生多執行緒安全。因為不可變物件不會被改變,所以它們可以被多執行緒共享,不需要增加額外的同步操作。字串池:上面的程式碼只會建立一個物件例項到Java Heap中,當建立str1時候,會去字串池中檢視是否已經有了這個字串,如果有,那麼把str1的引用直接指向這個字串例項上去,這樣便極大的節省了記憶體空間的使用。如果字串可變的話,那麼修改了其中一個物件,就會影響另外一個。
快取HashCode
當我們建立了一個字串物件時候,便生成了它的HashCode,因為是不可變,所以生成之後便可以快取起來,這樣用於HashMap中的key,便大大提高了查詢的速度。還有我們的Set集合,大家都知道Set集合是不可重複的集合,String類的不可變很好的支援了Set集合的設計思想。String類是基石正是因為有了以String類為代表的這些不可變類,才能為其他物件的構建提供了極大的便利,想想我們在編寫Java程式的時候,是不是大量的使用了String類。
-
3 # TonyDeng
為什麼會把這種資料設計為不可變的,只有理解C對字串的處理才能明白。我不可能在這裡長篇大論教你C是如何處理字元陣列的,這涉及儲存、修改和伸縮的演算法,也會觸及記憶體分配和重分配,很多,必須自己用C把這些都寫過,才能領會的。
簡單的結論:不管語言如何高階,最終底層的實現,都歸結到C那樣的基礎手法,逃不過,理解為什麼會如此,也是一樣要了解C是如何處理的。之所以把諸如String類資料設計為不可變,最主要的原因是當涉及資料長度伸縮時會觸發記憶體重分配,連資料的儲存地址也變了,會牽扯太多的副作用,尤其是使用指標訪問該資料的相關函式和執行緒,都會起連鎖反應,那是牽一髮動全身的。與其如此,為了效率和安全起見,不如把這種資料作為常量資料處理,它是不可變和修改的,只讀的,哪怕是修改其中一個字元,也要重新構造一個新的物件。事實上,用到字串的地方,絕不是僅僅改變其中幾個字元那麼簡單,長度變化是最常見的。
一般地,諸如Java、C#、C++這類高階語言,除了較為簡單的字串變更,頻率較少的,會採用類似String的資料型別,如果是在迴圈中頻繁大量變動的,要使用另外一種可變內容的資料型別,C#中是StringBulider型別,C++中是string型別,實際上是list資料結構,預分配空餘增長空間的,以耗費記憶體空間換時間效率。
-
4 # 程式猿W
我們舉例來說明:
String s = "a" + "b" + "c"; //就等價於String s = "abc";
String a = "a";
String b = "b";
String c = "c";
String s1 = a + b + c;
s1 這個就不一樣了,可以透過觀察其JVM指令碼發現s1的"+"操作會變成如下操作:
StringBuilder temp = new StringBuilder();
temp.append(a).append(b).append(c);
String s = temp.toString();
回覆列表
建立String物件的原理是這樣的:當成功建立一個String物件時,會同時建立兩個物件-一個在堆疊區域中儲存,一個在String常量池中儲存,往後對String物件的引用始終指向堆疊區域中的物件。
為什麼Java中的String是不可變的?因為String物件快取在String池中,由於快取的字串會在多個客戶端之間共享,如果其是可變的,那麼其中一個客戶端對String進行操作就會影響到其他所有的客戶端。例如,如果一個客戶端將String-"Java"修改為“JAVA”,則其他所有的客戶端也將看到該值,這在多客戶端時存在很大的風險。為了防止一個客戶端修改String而影響其他所有的客戶端,故將String定義為不可變(final)。這樣做的好處是沒有人可以透過擴充套件和覆蓋行為來破壞String所定義的值。