聊聊JAVA中 String類爲何不可變

前言

"個人風格比較偏傳統和經典" 小明說,"咱們在打扮本身的問題上仍是蠻冒險的...我以爲當你是隻狗的時候,穿什麼都hold的住!"java

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

前半年規劃人生,後半年開始規劃,最近發生的一些事情仍是讓本身倍感壓力的,生活能夠滿足常樂,但人生不能夠,若是你不把生命體驗到極致,也許會被將來的本身所鄙視。安全

前世此生

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

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

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

若是你仔細閱讀源碼註釋,你會發現這樣一句話:3d

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

大體意思就是String是個常量,從一出生就註定不可變。對象

我以爲到這裏各位小夥們應該就知道爲何String不可變了,戴了個final的帽子,官方註釋說明建立後不能被改變,可是爲何String要使用final修飾呢?blog

面試精選

在瞭解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。

相關文章
相關標籤/搜索