1. 字符串常量池
在 JVM 中,為了減少相同的字符串的重復(fù)創(chuàng)建腥沽,為了達到節(jié)省內(nèi)存的目的逮走。會單獨開辟一塊內(nèi)存,用于保存字符串常量今阳,這個內(nèi)存區(qū)域被叫做字符串常量池师溅。
2. 字符串的創(chuàng)建過程
當(dāng)代碼中出現(xiàn)雙引號形式(字面量)創(chuàng)建字符串對象時,JVM 會先對這個字符串進行檢查盾舌,如果字符串常量池中存在相同內(nèi)容的字符串對象的引用墓臭,則將這個引用返回;否則妖谴,創(chuàng)建新的字符串對象起便,然后將這個引用放入字符串常量池,并返回該引用窖维。
3. 在運行期將字符串內(nèi)容放入常量池中
除了以上方式之外榆综,還有一種可以在運行期將字符串內(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