String與常量池(JDK1.8)


---- 基礎知識

    String是final類, 並且其方法都被final修飾

    String通過char數組來保存字符串

    對String對象的任何操作都不會影響到原來的String對象, 所有的改變都會創建新String對象

---- 創建與內存場景分析

?--- 常量賦值

   代碼:

  

  內存圖:

 

  分析:對於常量賦值來說, 變量s1始終指向了字符串常量池的字符串(只有一份)

?--- 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)都只會在堆區創建該字符串對象, 並不會在常量池創建新生成的字符串

----String intern()方法

  用法解釋:

    當調用intern方法時,如果池已經包含與equals(Object)方法確定的相當於此String對象的字符串,則返回來自池的字符串。 否則,此String對象將添加到池中,並返回對此String對象的引用

舉個栗子

   代碼:

 

   內存圖:

分析:

    可以看出,是先在池里創建“a”好后,返回一個對象引用賦給堆里的對象new String("a"),也就s1所指向的地方,在堆里。通過調用 intern() 方法,在池里找到S1對象所對應的字符串,並且進行返回給S2對象,所以S2所指向的地方,在常量池里。

 舉個栗子

   代碼:

   

    內存圖:

    

     分析:由於常量池不存在ba, 所以返回堆區ba的地址並添加到常量池中, s2指向了常量池的inte指針

---- 談談 “+”

   若+號前后為常量,編譯期會處理

   若+號前后存在着變量,首先以最左邊的字符串為參數創建StringBuilder對象,然后依次對右邊進行append操作,最后將StringBuilder對象通過toString()方法轉換成String對象

 

 參考資料: https://blog.csdn.net/qq_26222859/article/details/73135660#commentBox


免責聲明!

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



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