String s="Hello"; s=s+"world!";這兩行代碼執(zhí)行后,原始的String對(duì)象中的內(nèi)容到底變了
String s="Hello"; s=s+"world!";這兩行代碼執(zhí)行后,原始的String對(duì)象中的內(nèi)容到底變了沒(méi)有?
答案是沒(méi)有變。因?yàn)镾tring是不可變類,不可變類,顧名思義就是說(shuō)類的實(shí)例是不可被修改的。實(shí)例的信息是在創(chuàng)建的時(shí)候提供,并且在整個(gè)生命周期中都不可改變。在這段代碼中,s原來(lái)指向一個(gè)String對(duì)象,內(nèi)容是“hello”,然后我們對(duì)s進(jìn)行了"+"操作,那么s所指向的那個(gè)對(duì)象是否發(fā)生了改變呢?答案是沒(méi)有。這時(shí),s不指向原來(lái)那個(gè)對(duì)象了,而指向了另一個(gè)String對(duì)象,內(nèi)容為”helloworld!",原來(lái)那個(gè)對(duì)象還存在內(nèi)存中,只是s這個(gè)引用變量不再指向他了。
通過(guò)上面的說(shuō)明,我們很容易得出一個(gè)結(jié)論,如果經(jīng)常對(duì)字符串進(jìn)行各種各樣的修改,或者說(shuō),不可預(yù)見(jiàn)的修改,那么使用String來(lái)代表字符串的話會(huì)引起很大的內(nèi)存開(kāi)銷。因?yàn)椋琒tring對(duì)象建立后不能改變,所以對(duì)于每一個(gè)不同的字符串,都需要一個(gè)String對(duì)象來(lái)表示。這時(shí),應(yīng)該考慮使用StringBuffer類,他允許修改,而不是每個(gè)不同的字符串都要生成一個(gè)新的對(duì)象。并且,這兩種類的對(duì)象轉(zhuǎn)換十分容易。
對(duì)于字符串常量,如果內(nèi)容相同,Java認(rèn)為它們代表同一個(gè)String對(duì)象。而用關(guān)鍵字new調(diào)用構(gòu)造器,總是會(huì)創(chuàng)建一個(gè)新的對(duì)象,無(wú)論內(nèi)容是否相同。
至于為什么要把String類設(shè)計(jì)成不可變類,是它的用途決定的。其實(shí)不只String,很多Java標(biāo)準(zhǔn)類庫(kù)中的類都是不可變的。在開(kāi)發(fā)一個(gè)系統(tǒng)的時(shí)候,我們有時(shí)候也需要設(shè)計(jì)不可變類,來(lái)傳遞一組相關(guān)的值,這也是面向?qū)ο笏枷氲捏w現(xiàn)。不可變類有一些優(yōu)點(diǎn),比如因?yàn)樗膶?duì)象是只讀的,所以多線程并發(fā)訪問(wèn)也不會(huì)有任何問(wèn)題。當(dāng)然也有一些缺點(diǎn),比如每個(gè)不同的狀態(tài)都要一個(gè)對(duì)象來(lái)代表,可能會(huì)造成性能上的問(wèn)題。所以Java標(biāo)準(zhǔn)類庫(kù)還提供了一個(gè)可變版本,即 StringBuffer。