聊聊JAVA中 String類為什么不可變


前言

"我的風格比較偏傳統和經典" 小明說,"我們在打扮自己的問題上還是蠻冒險的...我覺得當你是只狗的時候,穿什么都hold的住!"

哈哈哈,脫離單身狗快兩年了,生活中除了愛情,不變的還有對代碼的摯愛,總之始於熱愛,忠於愛情,陷於代碼。

前半年規划人生,后半年開始規划,最近發生的一些事情還是讓自己倍感壓力的,生活可以知足常樂,但人生不可以,如果你不把生命體驗到極致,也許會被未來的自己所鄙視。

前世今生

String不可變這個話題應該是老生長談了,你可以說它就是設計者的龜腚,然后巴拉巴拉說出一大堆優點,也可以說它忠於愛情,只要JVM存活,它便萬年不變。

String自打娘胎一出生就跟他們的兄弟姐妹不一樣,好好的娃被戴了一個final的帽子,以至於byte,int,short,long等基本類型的小伙們都不帶它玩。

但是,String並不是一個簡單的人設,如果各位小伙伴們仔細查閱其源碼,那可是浩浩盪盪的3000+行代碼了,如果你一個controller能這樣的代碼量也是非常不錯的。

如果你仔細閱讀源碼注釋,你會發現這樣一句話:

Strings are constant; their values cannot be changed after they are created

大致意思就是String是個常量,從一出生就注定不可變。

我覺得到這里各位小伙們應該就知道為什么String不可變了,戴了個final的帽子,官方注釋說明創建后不能被改變,但是為什么String要使用final修飾呢?

面試精選

在了解String不可變之前,我覺得有必要分析一道經典的面試題:

public class Apple {
	public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a==b);
        System.out.println(a.equals(b));
        System.out.println(a==c);
        System.out.println(a.equals(c));
	}
}

答案是:true、true、false、true

如圖所示,代碼中的abc對應個的abc:

我覺得有必要把a、b、c替換成小明、紅、光,abc替換成紅蘋果重新梳理一下流程:

  1. 小明想吃紅蘋果,小明的爸爸首先會在樹上尋找是否有紅蘋果,有的話,爸爸就說,這個蘋果歸你了,如果沒有,假設萬能的小明爸爸也可以給他造一個。

  2. 這時候小紅過來了,爸爸我也想吃那個紅蘋果,並且強烈要求要拿一個,就這樣小明和小紅共享了這個蘋果。

  3. 小光是個聽話的孩子,只要是紅蘋果就行,我可不想跟他倆爭什么,爸爸就這樣從超市里給小光買了一個紅蘋果。

  4. 小明和小紅的是同一個蘋果,這個是不變的事實,無論你怎么比較。

  5. 小紅,小明和小光的都是紅蘋果,但卻不是同一個蘋果。

  6. 你可以把蘋果樹理解成常量池,爸爸購買蘋果的過程理解為new對象,當然,舉例可能不是太恰當,只是為了大家更好的理解。

回到代碼本來來說,因為String太過常用,JAVA類庫的設計者在實現時做了個小小的變化,即采用了享元模式,每當生成一個新內容的字符串時,他們都被添加到一個共享池中,當第二次再次生成同樣內容的字符串實例時,就共享此對象,而不是創建一個新對象,但是這樣的做法僅僅適合於通過=符號進行的初始化。

需要說明一點的是,在object中,equals()是用來比較內存地址的,但是String重寫了equals()方法,用來比較內容的,即使是不同地址,只要內容一致,也會返回true,這也就是為什么a.equals(c)返回true的原因了。

不可變的好處

首先,我們應該站在設計者的角度思考問題,而不是覺得這不好,那不合理:

  • 可以實現多個變量引用堆內存中的同一個字符串實例,避免創建的開銷。

  • 我們的程序中大量使用了String字符串,有可能是出於安全性考慮。

  • 大家都知道HashMap中key為String類型,如果可變將變的多么可怕。

  • 當我們在傳參的時候,使用不可變類不需要去考慮誰可能會修改其內部的值,如果使用可變類的話,可能需要每次記得重新拷貝出里面的值,性能會有一定的損失。

其次,我們再分析有沒有更好的解決方案:

  • 然,對於我來說,並沒有!!!
  • 然,對於我來說,並沒有!!!
  • 然,對於我來說,並沒有!!!

總結

了解到String是不可變的,知道了常量池是怎么個東西。

重溫了面試題,有興趣的小伙伴也可以去閱讀下String的源碼,浩浩盪盪的3000+。

String 被new時是要創建對象的,+ 號拼接同理,程序中盡量不要使用 + 拼接,推薦使用StringBuffer或者StringBuilder。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM