1.聲明為final類(lèi)的目的
主要目的就是保證String是不可變(immutable)奈梳。不可變就是第二次給一個(gè)String 變量賦值的時(shí)候杈湾,不是在原內(nèi)存地址上修改數(shù)據(jù),而是重新指向一個(gè)新對(duì)象攘须,新地址
漆撞。下面看String類(lèi)源碼如何保證是不可變的:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[];
String類(lèi)的主力成員字段value是個(gè)char[ ]數(shù)組,而且是用final修飾的于宙。編譯器不允許把value指向另一個(gè)地址浮驳。但可以直接對(duì)數(shù)組元素修改
。為了保證這個(gè)數(shù)組元素不能修改捞魁,做了如下措施:
(1)所有String的方法里很小心的沒(méi)有去動(dòng)數(shù)組里的元素至会,沒(méi)有暴露內(nèi)部成員字段。
(2)避免被其他人繼承后破壞署驻,整個(gè)String設(shè)成final禁止繼承奋献。如果有一個(gè)String的引用,它引用的一定是一個(gè)String對(duì)象旺上,而不可能是其他類(lèi)的對(duì)象瓶蚂。
2.為什么要不String設(shè)計(jì)為不可變
- 從內(nèi)存角度來(lái)看
字符串常量池的要求:創(chuàng)建字符串時(shí),如果該字符串已經(jīng)存在于池中宣吱,則將返回現(xiàn)有字符串的引用窃这,而不是創(chuàng)建新對(duì)象。多個(gè)String變量引用指向同一個(gè)內(nèi)地地址
征候。如果字符串是可變的杭攻,用一個(gè)引用更改字符串將導(dǎo)致其他引用的值錯(cuò)誤。這是很危險(xiǎn)的疤坝。 - 緩存Hashcode
字符串的Hashcode在java中經(jīng)常配合基于散列的集合一起正常運(yùn)行兆解,這樣的散列集合包括HashSet、HashMap以及HashTable跑揉。不可變的特性保證了hashcode永遠(yuǎn)是相同的锅睛。不用每次使用hashcode就需要計(jì)算hashcode。這樣更有效率历谍。因?yàn)楫?dāng)向集合中插入對(duì)象時(shí)现拒,是通過(guò)hashcode判別在集合中是否已經(jīng)存在該對(duì)象了(不是通過(guò)equals方法逐個(gè)比較,效率低)望侈。 - 方便其它類(lèi)使用
其他類(lèi)的設(shè)計(jì)基于string不可變印蔬,如set存儲(chǔ)string,改變?cè)搒tring后set包含了重復(fù)值脱衙。 - 安全性
String被廣泛用作許多java類(lèi)的參數(shù)侥猬,例如網(wǎng)絡(luò)連接例驹、打開(kāi)文件等。如果對(duì)string的某一處改變一不小心就影響了該變量所有引用的表現(xiàn)陵究,則連接或文件將被更改眠饮,這可能導(dǎo)致嚴(yán)重的安全威脅。
不可變對(duì)象不能被寫(xiě)铜邮,所以不可變對(duì)象自然是線程安全的
仪召,因?yàn)椴豢勺儗?duì)象不能更改,它們可以在多個(gè)線程之間自由共享松蒜。