- 首先,在源代碼中用雙引號引起來的會自動進入常量池中(其實字符串對象是在堆中,然後常量池裏有個引用指向它,但是和直接說在常量池中似乎沒多大影響,下面也就這麼說了)
String s1 = new StringBuffer("he").append("llo").toString();
System.out.println(s1==s1.intern());//結果是true
這個he和llo都去池子裏面了。
- 然後,intern()方法在JDK1.7做了一點小改進,之前的做法是如果字符串是首次出現,那麼將字符串複製到常量池中,然後返回常量池中的引用;JDK1.7的做法是如果是首次出現,那麼在常量池中記下這個字符串的位置,然後直接返回這個引用。我這點兒語文我自己都覺得稀爛。。。。
隨便百度找的,基本就是《深入理解Java虛擬機》原文了。
文中說到"java"這個字符串並不是首次出現,它在這裏:
<img src="https://pic1.zhimg.com/v2-ce0ed85448ce4d79824c61d9e4705074_b.png" data-rawwidth="532" data-rawheight="127" class="origin_image zh-lightbox-thumb" width="532" data-original="https://pic1.zhimg.com/v2-ce0ed85448ce4d79824c61d9e4705074_r.png">在Oracle官網下載的JDK中rt.jar下可以找到這個類。當然如果你使用的是其他的JDK的話,可能並不是這樣子哦,比如我手裏這個JDK它是這樣的:
<img src="https://pic1.zhimg.com/v2-9c328996c81cf72305752aa69e30a45c_b.png" data-rawwidth="575" data-rawheight="128" class="origin_image zh-lightbox-thumb" width="575" data-original="https://pic1.zhimg.com/v2-9c328996c81cf72305752aa69e30a45c_r.png">所以用我手裏這個去跑結果是這面這樣子的:
<img src="https://pic3.zhimg.com/v2-13973bbcd75e35af7ce54fdfbcbe6296_b.png" data-rawwidth="700" data-rawheight="145" class="origin_image zh-lightbox-thumb" width="700" data-original="https://pic3.zhimg.com/v2-13973bbcd75e35af7ce54fdfbcbe6296_r.png">
- 解釋一下題主給的代碼的輸出
String s2 = new StringBuffer("word").toString();
System.out.println(s2==s2.intern());//結果是false
String s1 = new StringBuffer("he").append("llo").toString();
System.out.println(s1==s1.intern());//結果是true
append一下和上面的區別在於,一開始"hello"並沒有在常量池中,在池中的是"he"和"llo",再結合上面關於intern()方法的介紹,應該很好理解吧。(測試這種東西最好用一些亂七八糟的東西甚至是中文,比如上面的"java",其他地方已經出現過了,指不定什麼地方也出現了"Hello")
public synchronized String toString() {
return new String(value, 0, count);
}
String s2 = new StringBuffer("word").toString();
System.out.println(s2==s2.intern());//結果是false
1、word已經在字符串常量池中。
2、經過StringBuffer的toString以後,s2指向堆中新創建的對象。
3、s2.intern()拿到的是常量池中之前就存在的對象引用。
所以s2和s2.intern持有的不是同一個對象引用。
String s1 = new StringBuffer("he").append("llo").toString();
System.out.println(s1==s1.intern());//結果是true
2、經過StringBuffer的toString以後,s1指向堆中新創建的對象,同時這個對象也被保存到常量池中。
3、s1.intern()去常量池中拿到的對象引用也正是剛剛新建的對象。
所以s1和s1.intern持有的是同一個對象引用。