String是final類, 而且其方法都被final修飾數組
String經過char數組來保存字符串app
對String對象的任何操做都不會影響到原來的String對象, 全部的改變都會建立新String對象ui
?--- 常量賦值3d
代碼:指針
內存圖:對象
分析:對於常量賦值來講, 變量s1始終指向了字符串常量池的字符串(只有一份)blog
?--- new String("xxx");的運行
內存
代碼:字符串
源代碼:編譯
內存圖:
分析:
首先先來考慮一下這一句的執行過程,這句一共生成了兩個對象,分別是「abc」 和 new String("abc"),考慮類的加載對一個類只會執行一次,「abc」在類加載的時就已經建立駐留(若是該類加載以前已經有"abc"字符串駐留了,那麼不須要重複建立用於駐留的"abc"實例)。駐留的字符串是放在全局共享的字符串常量池中的。
在這段代碼後續被運行的時候,"abc"字面量對應的String實例已經固定了,不會再被重複建立。因此這段代碼將常量池中的對象複製一份放到heap中,而且把heap中的這個對象的引用交給s1 持有。因此能夠看到「abc」 是存在於常量池中 ,而s1指向堆裏的對象。
?---常量字符串的拼接(使用+)
代碼:
內存圖:
分析:
當一個字符串由多個字符串常量鏈接而成時,它本身確定也是字符串常量, 該字符串是在編譯期就能肯定。先是在池裏生成「a」和「b」,再經過拼接的方式生成"ab"
若一個String對象被final修飾, 而且形式爲final String s = "xxx";能夠將之看作是常量
?---很是量字符串拼接(使用+)
代碼:
內存圖:
分析:
這句話一共生成了5個對象,首先會先在池子生成「a」和「b」,而後會在堆裏生成對象new String("a") 和 new String("b),這兩個對象分別指向常量池的所對應的字符串,接着因爲「+」的做用下,建立了新的對象,這個對象經過利用以前的對象所指向的字符進行拼接生成「ab」,即這波操做是在堆裏實現的,不會將生成的"ab"放在常量池裏,此時以前的兩個對象已經沒有做用了,須要等待垃圾回收。
?---小結
無論是new String("XXX")和直接常量賦值, 都會在字符串常量池建立.只是new String("XXX")方式會在堆中建立一箇中轉站去指向常量池的對象, 而常量賦值的變量直接賦值給變量
當使用了變量字符串的拼接(+, sb.append)都只會在堆區建立該字符串對象, 並不會在常量池建立新生成的字符串
用法解釋:
當調用intern方法時,若是池已經包含與equals(Object)方法肯定的至關於此String對象的字符串,則返回來自池的字符串。 不然,此String對象將添加到池中,並返回對此String對象的引用
舉個栗子
代碼:
內存圖:
分析:
能夠看出,是先在池裏建立「a」好後,返回一個對象引用賦給堆裏的對象new String("a"),也就s1所指向的地方,在堆裏。經過調用 intern() 方法,在池裏找到S1對象所對應的字符串,而且進行返回給S2對象,因此S2所指向的地方,在常量池裏。
舉個栗子
代碼:
內存圖:
分析:因爲常量池不存在ba, 因此返回堆區ba的地址並添加到常量池中, s2指向了常量池的inte指針
若+號先後爲常量,編譯期會處理
若+號先後存在着變量,首先以最左邊的字符串爲參數建立StringBuilder對象,而後依次對右邊進行append操做,最後將StringBuilder對象經過toString()方法轉換成String對象