String 類不可變---基于安全性和效率考慮
String是Java中一個(gè)不可變的類,所以他一旦被實(shí)例化就無法被修改伪阶。不可變類的實(shí)例一旦創(chuàng)建煞檩,其成員變量的值就不能被修改。不可變類有很多優(yōu)勢栅贴。本文總結(jié)了為什么字符串被設(shè)計(jì)成不可變的斟湃。將涉及到內(nèi)存、同步和數(shù)據(jù)結(jié)構(gòu)相關(guān)的知識檐薯。
字符串池
字符串池是方法區(qū)中的一部分特殊存儲凝赛。當(dāng)一個(gè)字符串被被創(chuàng)建的時(shí)候,首先會去這個(gè)字符串池中查找坛缕,如果找到墓猎,直接返回對該字符串的引用。
下面的代碼只會在堆中創(chuàng)建一個(gè)字符串
String string1 = "abcd";
String string2 = "abcd";
下面是圖示:
如果字符串可變的話祷膳,當(dāng)兩個(gè)引用指向指向同一個(gè)字符串時(shí)陶衅,對其中一個(gè)做修改就會影響另外一個(gè)。(請記住該影響直晨,有助于理解后面的內(nèi)容)
緩存Hashcode
Java中經(jīng)常會用到字符串的哈希碼(hashcode)搀军。例如膨俐,在HashMap中,字符串的不可變能保證其hashcode永遠(yuǎn)保持一致罩句,這樣就可以避免一些不必要的麻煩焚刺。這也就意味著每次在使用一個(gè)字符串的hashcode的時(shí)候不用重新計(jì)算一次,這樣更加高效门烂。
在String類中乳愉,有以下代碼:
private int hash;//this is used to cache hash code.
以上代碼中hash變量中就保存了一個(gè)String對象的hashcode,因?yàn)镾tring類不可變屯远,所以一旦對象被創(chuàng)建蔓姚,該hash值也無法改變。所以慨丐,每次想要使用該對象的hashcode的時(shí)候坡脐,直接返回即可。
使其他類的使用更加便利
在介紹這個(gè)內(nèi)容之前房揭,先看以下代碼:
HashSet set = new HashSet();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));
for(String a: set)
a.value = "a";
在上面的例子中备闲,如果字符串可以被改變,那么以上用法將有可能違反Set的設(shè)計(jì)原則捅暴,因?yàn)镾et要求其中的元素不可以重復(fù)恬砂。上面的代碼只是為了簡單說明該問題,其實(shí)String類中并沒有value這個(gè)字段值蓬痒。
安全性
String被廣泛的使用在其他Java類中充當(dāng)參數(shù)泻骤。比如網(wǎng)絡(luò)連接、打開文件等操作乳幸。如果字符串可變瞪讼,那么類似操作可能導(dǎo)致安全問題。因?yàn)槟硞€(gè)方法在調(diào)用連接操作的時(shí)候粹断,他認(rèn)為會連接到某臺機(jī)器,但是實(shí)際上并沒有(其他引用同一String對象的值修改會導(dǎo)致該連接中的字符串內(nèi)容被修改)嫡霞∑柯瘢可變的字符串也可能導(dǎo)致反射的安全問題,因?yàn)樗膮?shù)也是字符串诊沪。
代碼示例:
boolean connect(string s){
if (!isSecure(s)) {
throw new SecurityException();
}
//如果s在該操作之前被其他的引用所改變养筒,那么就可能導(dǎo)致問題。
causeProblem(s);
}
不可變對象天生就是線程安全的
因?yàn)椴豢勺儗ο蟛荒鼙桓淖兌艘Γ运麄兛梢宰杂傻卦诙鄠€(gè)線程之間共享晕粪。不需要任何同步處理。
總之渐裸,String被設(shè)計(jì)成不可變的主要目的是為了安全和高效巫湘。所以装悲,使String是一個(gè)不可變類是一個(gè)很好的設(shè)計(jì)。
參考:http://www.jb51.net/article/117185.htm