String intern原理

String intern在Java6 7 8中實現原理不一樣,本文僅針對Java8的原理進行分析

intern方法解釋

首先來看interna方法的說明:java

/**
     * Returns a canonical representation for the string object.
     * <p>
     * A pool of strings, initially empty, is maintained privately by the
     * class {@code String}.
     * <p>
     * When the intern method is invoked, if the pool already contains a
     * string equal to this {@code String} object as determined by
     * the {@link #equals(Object)} method, then the string from the pool is
     * returned. Otherwise, this {@code String} object is added to the
     * pool and a reference to this {@code String} object is returned.
     * <p>
     * It follows that for any two strings {@code s} and {@code t},
     * {@code s.intern() == t.intern()} is {@code true}
     * if and only if {@code s.equals(t)} is {@code true}.
     * <p>
     * All literal strings and string-valued constant expressions are
     * interned. String literals are defined in section 3.10.5 of the
     * <cite>The Java&trade; Language Specification</cite>.
     *
     * @return  a string that has the same contents as this string, but is
     *          guaranteed to be from a pool of unique strings.
     */

簡單來講,在Java8中,String類維護了一個字符串常量池(注意此常量池在運行期間位於堆中),當調用intern方法時,首先在常量池中查看是否已有相同的字符串(字符串是否相同使用String的equal方法判斷),若是常量池中已有,則直接返回該字符串的引用,若是沒有,則將當前字符串對象加入常量池中,並返回當前字符串的引用。express

字符串建立

字符串的建立,若是使用 new 建立時,是在堆中建立字符串對象,若是直接使用字面量,則先看常量池中是否有相等的字符串,若是有,則返回此字符串的引用,若是沒有,則在常量池中建立。優化

舉例

下面舉例說明this

String s1 = new String(String.valueOf(11));
String s2 = s1.intern();

這裏使用String.valueOf(11)而不是「11」,是爲了先說明非字符串常量的狀況。spa

執行第一行代碼時,內存中的數據如圖1所示:
在堆中建立String "11" 對象,在棧中建立變量s1,指向String對象。code

執行第二行代碼時,調用String對象的intern方法,此時常量池中沒有 "11",因此將"11"加入到常量池中,返回"11"對象的引用,賦值給s2, 內存中數據分佈如圖2所示:
image.pngorm

因此此時s1==s2,執行結果:
image.png對象

下面看下字面量字符串和常量字符串的狀況blog

String s1 = "11";  
String s2 = new String("11");  
String s3 = s2.intern();  
System.out.println(s1 == s2);  
System.out.println(s2 == s3);  
System.out.println(s1 == s3);

對於字面量字符串和常量字符串是直接在string pool中建立, 因此s1指向常量池中的字符串對象;
s2使用new操做符,在堆中建立,因此s2指向堆中的字符串對象;
s2調用intern方法後,由於常量池中已經有「11」的字符串對象,因此直接返回常量池中的字符串引用。 內存中的數據分佈如圖3:內存

image.png

因此執行結果是:
image.png

優化配置

string pool是使用Map結構存儲字符串及引用,若是想要增長string pool的大小,能夠設置JVM參數:

-XX:StringTableSize=1000003

Java8中默認是60013,設置的值最好是素數,以減小Hash碰撞,提升查詢效率。

參考:
https://www.journaldev.com/79...
http://java-performance.info/...
https://www.baeldung.com/java...

相關文章
相關標籤/搜索