針對jdk1.7及1.7+之后的場景:
場景1?
String s ="a" +"b";
String s1 ="ab";
System.out.println(s==s1);
結(jié)果為true,"a" +"b"編譯后直接優(yōu)化為字符串的"ab"。運行的時候“ab”會在字符串常量池中創(chuàng)建一個"ab"然后地址返回給s,s1="ab",會從字符串常量查找"ab"的常量,查到后將引用地址返回給s1。s和s1指向的是字符串常量池中同一個地址,所以為true.
結(jié)論:
1 "ab"會在字符串常量池中生成一個"ab"對象。字符串常量池中數(shù)據(jù)不會重復(fù)。
2?通過編譯后的文件可以看到,"a" +"b"只會在常量池中生成一個對象"ab"。直接經(jīng)過編譯后就只有"ab",看不出"a","b"的信息
場景2
String s = new String("ab")創(chuàng)建幾個對象。

通過查看編譯后的字節(jié)碼文件,可以看到有2個對象
1 在堆中new 的一個String對象
2 在字符串常量池中創(chuàng)建一個"ab"的對象
注意:這個時候s引用指向的是堆中的String對象,而不是字符串常量池stringtable中的對象。
所以有:
String s =new String("ab");
String s1 ="ab";
System.out.println(s==s1);
結(jié)果為false,s指向的是堆中創(chuàng)建的對象,s1指向的是字符串常量池中的對象。
場景3:
String s =new String("a") +new String("b");
String s1 ="ab";
System.out.println(s==s1);
這里涉及2個問題:
1?new String("a") +new String("b")創(chuàng)建幾個對象
jdk1.7之后優(yōu)化字符串的+操作會使用stringBuilder的append()操作。
創(chuàng)建的對象(總共6個):
①new StringBuilder()對象
②堆中一個new String("a")對象
③字符串常量池中一個a對象
④堆中一個new String("b")對象
⑤字符串常量池中一個b對象
⑥StringBuilder()調(diào)用toString()在堆中生成的一個對象。
2?s==s1結(jié)果為false。一個是堆中對象,一個是字符串常量池中的對象。
場景4?
String s1 ="a";
String s2 ="b";
String s3 = s1+s2;
String s4 ="ab";
System.out.println(s3==s4);
結(jié)果為false,字符串的+號操作,使用StringBuilder的append方法進行處理。
場景5
final String s1 ="a";
final String s2 ="b";
String s3 = s1+s2;
String s4 ="ab";
System.out.println(s3==s4);
結(jié)果為true,使用final修飾的變量就是一個常量,編譯器在編譯階段可以直接確定s3的值。不會使用StringBuilder進行處理。s3直接指向常量池中"ab",所以s3==s4。
場景6
final String s1 ="a";
String s3 = s1+"b";
String s4 ="ab";
System.out.println(s3==s4);
結(jié)果為true,編譯器優(yōu)化s3直接為"ab"
場景7
final String s1 =new String("a");
String s3 = s1+"b";
String s4 ="ab";
System.out.println(s3==s4); //false
結(jié)果為false,此時的"a"有2個對象。一個是堆中通過 new String()生成的對象,一個是字符串常量池中的對象。s1指向的是堆中new的對象,而堆中new的對象是在運行期才能確定的,所以這個時候雖然s1是一個final修飾的常量,但是編譯器還是會當(dāng)做一個不確定的量使用(new的對象在運行時才能確定),所以當(dāng)編譯器遇到+操作會使用StringBuilder進行處理。結(jié)果為false。
場景8
final String s1 =new String("a");
String s3 = s1+"b";
s3.intern();
String s4 ="ab";
System.out.println(s3==s4);? //true
重要:
結(jié)果為true,String s3 = s1+"b";這個操作會變成stringBuilder的toString()操作,返回的是堆中的對象"ab",這個時候字符串常量池中并沒有"ab"。調(diào)用s3.intern()后,會在常量池中創(chuàng)建一個"ab"的字符串常量,但是此時其實堆中是先有了一個調(diào)用toString()方法new出來的對象,jvm會復(fù)用這個對象,將常量池中的"ab"這個對象直接執(zhí)行堆中new的對象,這個時候再去String s4 ="ab",會指向同一個地址。所以結(jié)果為true。
場景9?
String s1 =new String("a");
s1.intern();
String s2 ="a";
System.out.println(s1==s2);? //false
結(jié)果為false。a在堆中2個對象,一個是字符串常量池中,一個在new的對象中。這個時候s1指向的是堆中new的對象。調(diào)用s1.intern();這個方法會判斷字符串常量池中是否有s1這個對象,如果存在就結(jié)果返回。沒有就創(chuàng)建一個。所以這個時候調(diào)用s1.intern()。其實是無效的。s1指向的是堆中new的地址,s2指向的是常量池中的地址。所以結(jié)果為false。