前提一:關(guān)于==和equals
- 對于==锉矢,基本類型比較的是字面量即值梯嗽,引用類型比較的是堆地址;
- 對于equals方法沽损,基本類型沒有這種寫法灯节,大部分引用類型比較的是堆地址,因?yàn)橐妙愋偷捻敿壐割怬bject的equals方法內(nèi)部使用==直接比較绵估,所以引用類型在沒有重寫equals方法的時候炎疆,使用equals方法就等價于==的堆地址比較。
- 特殊情況:String引用類型重寫了equals方法壹士,equals比較的是字面量即字符串的值磷雇。所以String的==比較堆地址,equals比較字面量躏救。
前提二:關(guān)于JVM的內(nèi)存劃分唯笙。涉及到方法區(qū)(非堆螟蒸、元空間)與堆的關(guān)系,String Pool在JDK8中從非堆移動到堆內(nèi)存中等等這些技術(shù)問題在知乎https://www.zhihu.com/question/29884421/answer/113785601@胖君的回答非常棒崩掘。
- String Pool字符串常量池中存放的不是字面量而是堆中字符串字面量的引用七嫌。JVM會在一個String被=直接賦值時,調(diào)用equals方法比較字面量苞慢,而new String不會比較字面量诵原,直接開辟堆空間,這也是字符串的=直接賦值與new String的重要區(qū)別挽放。
- 一旦Java源文件編譯后的類字節(jié)碼被加載進(jìn)入JVM方法區(qū)或者說元空間绍赛,類中的原始字符串常量就存在于String Pool中,運(yùn)行時只有棧中拉取相關(guān)方法時辑畦,棧中字符串變量才會依據(jù)String Pool來判斷最終指向堆內(nèi)存String字面量吗蚌,這種指向才有意義。
前提三:字符串的+相加的不同情況區(qū)分纯出。
- 形如String combo1 = str1 + str2;這種語句是引用變量(指向堆)與引用變量(指向堆)相加蚯妇,結(jié)果必然是new String新開辟一個String堆內(nèi)存。
- 形如String combo2 = "a" + "bc";這種語句是棧中直接執(zhí)行暂筝,結(jié)果得到一個棧中字符串變量箩言,這時候JVM會去String Pool比較字面量,如果有焕襟,則棧中字符串變量combo2指向已有的堆內(nèi)存陨收,如果沒有則開辟新空間。
實(shí)際測試結(jié)果
public class StringInJVM {
//private static String str = "abc";
@Test
public void test() {
/**
* 基本:比較字符串的=直接賦值和new String的多次賦值
*/
String basic1 = "basic";
String basic2 = "basic";
String basic3 = new String("basic");
String basic4 = new String("basic");
System.out.println(basic1 == basic2); //true
System.out.println(basic1 == basic3); //false
System.out.println(basic3 == basic4); //false
/**
* 升級:比較字符串+運(yùn)算后的=內(nèi)存地址
*/
String str = "abc";
String str1 = "a";
String str2 = "bc";
String combo1 = str1 + str2;
String combo2 = "a" + "bc";
//棧中引用變量相加胧洒,結(jié)果直接new畏吓。如果直接字面量"a"+"bc"就不一樣
System.out.println(str == combo1); //false
System.out.println(str == combo2); //true
System.out.println(combo1 == combo2); //false
System.out.println(str == combo1.intern()); //true
System.out.println(str == combo2.intern()); //true
/**
* 升級
*/
String s1 = "ABC";
String s2 = "A" + "BC"; //棧中字面量直接相加,結(jié)果也根據(jù)字面量決定是否new堆
String s3 = new String(s1); //new堆
String s4 = new String("A" + "BC"); //new堆
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); //false
System.out.println(s1 == s4); //false
System.out.println(s2 == s3); //false
System.out.println(s2 == s4); //false
System.out.println(s3 == s4); //false
}
}