1. 字符串常量池
在 JVM 中,為了減少相同的字符串的重復(fù)創(chuàng)建,為了達(dá)到節(jié)省內(nèi)存的目的。會單獨(dú)開辟一塊內(nèi)存,用于保存字符串常量,這個內(nèi)存區(qū)域被叫做字符串常量池。
2. 字符串的創(chuàng)建過程
當(dāng)代碼中出現(xiàn)雙引號形式(字面量)創(chuàng)建字符串對象時,JVM 會先對這個字符串進(jìn)行檢查,如果字符串常量池中存在相同內(nèi)容的字符串對象的引用,則將這個引用返回;否則,創(chuàng)建新的字符串對象,然后將這個引用放入字符串常量池,并返回該引用。
3. 在運(yùn)行期將字符串內(nèi)容放入常量池中
除了以上方式之外,還有一種可以在運(yùn)行期將字符串內(nèi)容放置到字符串常量池的辦法,那就是使用 intern
intern 的功能很簡單:
在每次賦值的時候使用 String 的 intern() 方法,如果常量池中有相同值,就會重復(fù)使用該對象,返回對象引用。
舉例:
當(dāng)我們不使用 intern() 方法時
public static void main(String[] args) {
String str1 = "test";
String str2 = new String("test");
System.out.println(str2 == str1); // false
}
可以看到我們首先通過字面量在字符串常量池中添加了 test 的字符,但是當(dāng)我們使用 new String("test") 方法時,str2 中新生成了一個對象,并且對象的引用并沒有指向字符串常量池中的 test 字符。我們可以在創(chuàng)建 String 對象時通過調(diào)用 intern() 方法,如果常量池中有相同值,就會重復(fù)使用該對象,返回對象引用。
當(dāng)我們使用 intern() 方法時
public static void main(String[] args) {
String str1 = "test";
String str2 = new String("test").intern();
System.out.println(str2 == str1); //true
}
當(dāng)我們使用了 intern() 方法后,由于字符串常量池中存在相同的 test 字符串,所以 str2 對象的引用直接指向了字符串常量池中
當(dāng)我們都通過
new String()來創(chuàng)建字符串時
public static void main(String[] args) {
String str1 = new String("test");
String str2 = new String("test");
System.out.println(str2 == str1); // false
}
這里創(chuàng)建了兩個 String 的對象,但是由于都是 new 出來的對象,所以他們所指向的對象引用都各不相同
通過
intern()方法來管理new String()對象
public static void main(String[] args) {
String str1 = new String("test").intern();
String str2 = new String("test").intern();
System.out.println(str2 == str1); //true
}
可以看到結(jié)果為 true, 當(dāng) str1 調(diào)用 intern() 方法時,JVM 會去字符串常量池中查看常量池中是否存在 test 的字符串,如果不存在則將 test 字符串放入字符串常量池中,當(dāng)我們調(diào)用第二次 new String().intern() 方法創(chuàng)建對象時,JVM 繼續(xù)去字符串常量池中查詢是否存在 test 的字符串常量,此處存在則返回與 str1 相同的引用。
定義引用自 Java 工程師成神之路 - intern