06 StringTable

1. String的基本特性

  • String:字符串,使用一對""引號來表示。
    • String s1 = "hello"; //字面量的定義方式
    • String s2 = new String("hello");
  • String聲明為final的,不可被繼承
  • String實現了Serializable接口,表示字符串是支持序列化的;實現了Comparable,表示String可以比較大小。
  • String在JDK8及以前內部定義了final char[] value 用于存儲字符串數據。JDK9時改為byte[]。
  • String:代表不可變的字符序列。簡稱不可變性。
    • 當對字符串重新賦值時,需要重寫指定內存區域賦值,不能使用原有的value進行賦值。
    • 當對現有的字符串進行連接操作時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值。
    • 當調用String的replace()方法修改指定字符或字符串時,也需要重新指定內存區域賦值,不能使用原有的value進行賦值。
  • 通過字面量的方式(區別于new)給一個字符串賦值,此時的字符串值聲明在字符串常量池中
  • 字符串常量池中是不會存儲相同內容的字符串的。
    • String的String Pool是一個固定大小的Hashtable,默認值大小長度是1009。如果放進String Pool的String非常多,就會造成Hash沖突嚴重,從而導致鏈表會很長,而鏈表長了后直接會造成的影響就是當調用String.intern時性能會大幅下降。
    • 使用-XX:StringTableSize可設置StringTable的長度
    • 在JDK6中StringTable是固定的,就是1009的長度,所以如果常量池中的字符串過多就會導致效率下降很快。StringTableSize設置沒有要求
    • 在JDK7中,StringTable的長度默認值是60013
    • JDK8開始,設置StringTable的長度的話,1009是可設置的最小值。

2. String的內存分配

  • 在Java語言中有8種基本數據類型和一種比較特殊的類型String。這些類型為了使它們在運行過程中速度更快、更節省內存,都提供了一種常量池的概念。
  • 常量池就類似于一個Java系統級別的緩存。8種基本數據類型的常量池都是系統協調的,String類型的常量池比較特殊,它的主要使用方法有兩種:
    • 直接使用雙引號聲明出來的String對象會直接存儲在常量池中。比如String info = "hello";
    • 如果不是雙引號聲明的String對象,可以使用String提供的intern()方法。
  • Java6及以前,字符串常量池存放在永久代。
  • Java7中Oracle的工程師對字符串的邏輯做了很大的改變,即將字符串常量池的位置調整到Java堆內。
    • 所有的字符串都保存在堆(Heap)中,和其它普通對象一樣,這樣可以讓你在進行調優應用時僅需要調整堆大小就可以了。
    • 字符串常量池概念原本使用得比較多,但是這個改動使得我們有足夠得理由讓我們重新考慮在Java7中使用String.intern()。
  • Java8永久代變為元空間,字符串常量仍在堆中。

3. String的基本操作

Java語言規范里要求完全相同的字符串字面量,應該包含同樣的Unicode字符序列(包含同一份碼點序列的常量),并且必須是指向同一個String類實例。

4. 字符串拼接操作

  • 常量與常量的拼接結果在常量池,原理是編譯期優化。
  • 常量池中不會存在相同內容的常量。
  • 只要其中有一個是變量s1 = s2 + "hello";//s2不能用final修飾),結果就在堆中。變量拼接的原理是StringBuilder。
  • 如果拼接的結果調用intern()方法,則主動將常量池中還沒有的字符串對象放入池中,并返回此對象地址。

    intern():首先判斷字符串常量池中是否存在對應的字符串值,如果存在,則返回常量池中該字符串的地址;如果不存在,則在常量池中加載該字符串,并返回該字符串的地址。

5. intern()的使用

如果不是使用雙引號聲明的String對象,可以使用String提供的intern方法:intern方法會從字符串常量池中查詢當前字符串是否存在,若不存在就會將當前字符串放入常量池中。
表達式("a" + "b" + "c").intern() == "abc"的值必定是true。
intern()方法可以確保字符串在內存里只有一份拷貝,這樣可以節約內存空間,加快字符串操作任務的執行速度。注意,這個值會被存放在字符串內部池(String Intern Pool)。

JDK6 vs JDK7/8

  1. JDK1.6中,將這個字符串對象嘗試放入串池。
  • 如果串池中有,則并不會放入。返回已有的串池中的對象的地址。
  • 如果沒有,會把此對象復制一份,放入串池,并返回串池中的對象地址。
  1. JDK1.7起,將這個字符串對象嘗試放入串池。
  • 如果串池中有,則并不會放入。返回已有的串池中的對象的地址。
  • 如果沒有,會把對象的引用地址復制一份,放入串池,并返回串池中的對象地址。

當程序中存在大量重復的字符串時,使用intern()可以節省內存空間。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 【部分內容來自網絡,侵刪】 常用類 Object object類是所有類的根類。 toString 返回方法的字符...
    昵稱該起什么好呢閱讀 524評論 0 0
  • 目錄介紹 6.0.0.1 運行時數據區域有哪些?Java虛擬機棧是做什么的?本地方法棧又是做什么的? 6.0.0....
    楊充211閱讀 454評論 0 1
  • string的相關特性 String 被聲明為 final,因此它不可被繼承。確保String不可變。 ...
    山邊有個小賣部閱讀 139評論 0 0
  • String 的聲明 由 JDK 中關于String的聲明可以知道: 不同字符串可能共享同一個底層char數組,例...
    CodeKing2017閱讀 1,653評論 1 2
  • 首先,來一道String的考題,代碼如下: 先不著急給出答案,我們來一步一步得進行分析,爭取覆蓋String大部分...
    HRocky閱讀 304評論 0 0