實驗背景:
在看《深入理解java虛擬機》中的介紹字符串常量池的下段文件,產生了一些疑問,故做此實驗。
實驗環境: jdk1.8
測試代碼1:
public static void main(String[] args) {
String s1=new StringBuilder("計算機").append("技術").toString();
String s2=new StringBuilder("計算機").append("技術").toString();
String s3=new StringBuilder("編程思想").toString();
System.out.println(s2.intern()==s2);
System.out.println(s2=="計算機技術");
System.out.println(s2.intern()=="計算機技術");
System.out.println(s1.intern()==s1);
System.out.println(s1.intern()==s2);
System.out.println(s2.intern()==new String("計算機技術"));
System.out.println(s3.intern()==s3);
System.out.println(s3.intern()=="編程思想");
}
測試1結果:true true true false true false false true
運行過程猜想:s1 創建了一個用StringBuilder創建了一個 "計算機技術"的String對象放在堆中,常量池中放入了兩個字符串"計算機"、"技術",並沒有放入"計算機技術”此字符串。因爲已有了"計算機"、"技術" 這兩個字符串,所以s2的過程僅僅在堆中創建了一個 "計算機技術"的String對象。 s3的創建過程類似於new String("編程思想"),先在常量池中放入字符串“變成思想”,再在堆中創建了一個“編程思想"的String對象。
結果分析:s2.intern()方法執行時,因常量池中並沒有"計算機技術”此字符串,所以此方法在常量池中創建了一個 "計算機技術”字符串的引用,此引用指向 s2,所有 第一個結果爲true.
在比較s2.intern() 和 “計算機技術” 時,因前面運行了一次s2.intern()方法,所以常量池中存在“計算機技術”此字符串常量(引用,這裏指向s2所指的對象),故也返回true,
同理第三個條也返回true。
因爲常量池中已有“編程思想”這個常量的引用,s1.intern()方法返回的即此引用所指的對象,所以第四條false,第五條true。
s2.intern()和new String()對比肯定返回false。第六條false。
s3在創建的時候已經向常量池中放入“變成思想”常量,所以s3.intern()返回的即常量池中的對象,不是s3這個對象。因此第七條false,第八條true.
測試代碼2:
public static void main(String[] args) {
String s1=new StringBuilder("計算機").append("技術").toString();
String s2=new StringBuilder("計算機").append("技術").toString();
System.out.println("計算機技術"==s2.intern());
System.out.println(s2.intern()==s2);
System.out.println(s2=="計算機技術");
System.out.println(s2.intern()=="計算機技術");
System.out.println(s1.intern()==s1);
System.out.println(s1.intern()==s2);
System.out.println(s1.intern()=="計算機技術");
}
運行結果:true false false true false false true
運行過程猜想:相比於測試1 ,這裏主要把"計算機技術"==s2.intern() 這一步放在最前面,並把“計算機技術”放在左邊,運行到這一步時,jvm會先把“計算機技術” 放入常量池 ,再執行s2.intern()方法。
結果分析:因爲s1、s2都還未執行intern()方法,所以常量池中不會有引用指向這兩個對象,而是直接保存的是"計算機技術"這個常量,故運行結果爲以上。
總結:用StringBuilder拼接字符串的時候,不會在常量池中保存最後拼成的結果,使用intern()方法,若常量池中沒有此字符串或者其引用則會在常量池中保存此引用,並指向堆中對象(這種對象是否會被gc???),
另外再提一下,使用StringBuilder拼接的好處是String是final類,每次拼接都會再創建一個對象。
使用String s="嘻嘻"+"哈哈"+"嘿嘿"; 其實編譯器會優化成 s="嘻嘻哈哈嘿嘿"; 即會在常量池中放入了一個常量。