對String不可變的理解

一直有寫博客的打算换淆,由于種種原因沒有開始,今天在公司正好討論到了String這個特殊的類舔涎,準備開啟自己的博客之旅。
作為Java語言中應用最廣泛的String類逗爹,也可以算得上是最特殊的一個類亡嫌,我們非常有必要深入了解它。
在《Thinking in java》第四版中有提到掘而,“String類中每一個看起來會修改String值的方法挟冠,實際上都是創(chuàng)建了一個全新的String對象,以包含修改后的字符串內容镣屹。而最初的String對象則絲毫未動圃郊。”
我們來看一下最常見的String方法replace(char oldChar女蜈, char newChar)持舆。

public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */
while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
}
在源碼中我們可以很明顯的看到replace方法調用之后返回的是一個新的String對象色瘩,也就是原來的String對象根本沒有改變。
我們可以做一個小測試逸寓。

public static void main(String[] args) {
String a = "abc";
StringBuilder sb = new StringBuilder("ccc");
System.out.println(new Test1().test(a));
System.out.println(a);
System.out.println(new Test1().test2(sb));
System.out.println(sb);
}
//不可變的String
public String test(String a) {
a += "bb";
return a;
}
//可變的StringBuilder
public StringBuilder test2(StringBuilder sb) {
return sb.append("xx");
}/* Output
abcbb
abc
cccxx
cccxx
*/
通過對比我們可以發(fā)現原來的String對象并沒有發(fā)生改變居兆,返回的是一個新的String對象,而可變的StringBuilder在進行方法調用之后竹伸,原來的對象已經發(fā)生了改變泥栖。
翻開JDK源碼。

public final class String
implements java.io.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
...
}
首先Strng類用final修飾勋篓,說明無法繼承String吧享。再看下面String類的主成員字段是一個value字符數組,用final修飾譬嚣,不可改變钢颂。不過雖然不能改變,也只是無法改變value這個引用地址拜银。指向的內容依然是可以改變的殊鞭。除此之外還有一個hash變量,是該String對象的哈希值緩存尼桶〔俨樱看一下例子,

public static void main(String[] args) {
final char value[] = { 'a', 'b', 'c' };
char another[] = { 'e', 'f', 'g' };
value = another;
}
編譯器間報錯泵督,編譯器不允許我把value的引用指向heap內存中另外的地址趾盐。不過只要改變數組元素,就可以搞定幌蚊。

public static void main(String[] args) {
final char value[] = { 'a', 'b', 'c' };
value[0] = 'b';
System.out.println(value);
}/* Output:
bbc
*/
value字符數組內容已經被改變了谤碳。
所以String不可變,其實是因為String方法沒有動value數組的元素溢豆,沒有暴露內部成員字段。String被final修飾瘸羡,也導致整個String無法被繼承漩仙,不被破壞。
其實研究到這里犹赖,腦海中已經有了一個大膽的想法队他,雖然value數組引用沒有暴露,通過一般途徑無法獲取到峻村,不過我們大可以用反射來訪問私有成員麸折。

public static void testReflection() throws Exception {
//創(chuàng)建字符串"Hello World", 并賦給引用s
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//獲取String類中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");
//改變value屬性的訪問權限
valueFieldOfString.setAccessible(true);
//獲取s對象上的value屬性的值
char[] value = (char[])valueFieldOfString.get(s);
//改變value所引用的數組中的第5個字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World
}
在這個過程中s引用始終指向同一個對象粘昨,在反射前后垢啼,這個對象被改變了窜锯,也就是通過反射可以修改所謂的“不可變”對象。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末芭析,一起剝皮案震驚了整個濱河市锚扎,隨后出現的幾起案子,更是在濱河造成了極大的恐慌馁启,老刑警劉巖驾孔,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異惯疙,居然都是意外死亡翠勉,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門霉颠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來对碌,“玉大人,你說我怎么就攤上這事掉分〖蠡海” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵酥郭,是天一觀的道長华坦。 經常有香客問我,道長不从,這世上最難降的妖魔是什么惜姐? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮椿息,結果婚禮上歹袁,老公的妹妹穿的比我還像新娘。我一直安慰自己寝优,他們只是感情好条舔,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著乏矾,像睡著了一般孟抗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钻心,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天凄硼,我揣著相機與錄音,去河邊找鬼捷沸。 笑死摊沉,一個胖子當著我的面吹牛,可吹牛的內容都是我干的痒给。 我是一名探鬼主播说墨,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼骏全,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了婉刀?” 一聲冷哼從身側響起吟温,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎突颊,沒想到半個月后鲁豪,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡律秃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年爬橡,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棒动。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡糙申,死狀恐怖,靈堂內的尸體忽然破棺而出船惨,到底是詐尸還是另有隱情柜裸,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布粱锐,位于F島的核電站疙挺,受9級特大地震影響,放射性物質發(fā)生泄漏怜浅。R本人自食惡果不足惜铐然,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望恶座。 院中可真熱鬧搀暑,春花似錦、人聲如沸跨琳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脉让。三九已至樟氢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間侠鳄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工死宣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留伟恶,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓毅该,卻偏偏與公主長得像博秫,于是被迫代替她去往敵國和親潦牛。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法挡育,類相關的語法巴碗,內部類的語法,繼承相關的語法即寒,異常的語法橡淆,線程的語...
    子非魚_t_閱讀 31,644評論 18 399
  • 從網上復制的,看別人的比較全面母赵,自己搬過來逸爵,方便以后查找。原鏈接:https://www.cnblogs.com/...
    lxtyp閱讀 1,346評論 0 9
  • 隨著他的背影遠去 心里不是滋味 就剛剛 他三歲小女兒想吃那個糖葫蘆 但他身上沒有錢 唯一的零錢是他們回家坐公交的車...
    88青青子衿閱讀 199評論 0 0
  • (萬尚學習會)打卡第148天 姓名:陸春菊 部門:財務部 組別:反省一組 【知~學習】 《京瓷哲學》001部分:第...
    陸春菊閱讀 20,610評論 0 0
  • 經過昨天的情緒低落真正感覺到了什么叫簡直停不下來凹嘲,一種停下來會不舒服的感覺师倔,從此不知“堅持”為何物,只管去做自己想...
    李章文閱讀 116評論 0 0