Java中String字符串的==與equals的區(qū)別以及=賦值與new String的區(qū)別等

前提一:關(guān)于==和equals

  • 對于==,基本類型比較的是字面量即值,引用類型比較的是堆地址;
  • 對于equals方法,基本類型沒有這種寫法,大部分引用類型比較的是堆地址,因?yàn)橐妙愋偷捻敿壐割怬bject的equals方法內(nèi)部使用==直接比較,所以引用類型在沒有重寫equals方法的時(shí)候,使用equals方法就等價(jià)于==的堆地址比較。
    • 特殊情況: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會在一個(gè)String被=直接賦值時(shí),調(diào)用equals方法比較字面量,而new String不會比較字面量,直接開辟堆空間,這也是字符串的=直接賦值與new String的重要區(qū)別。
  • 一旦Java源文件編譯后的類字節(jié)碼被加載進(jìn)入JVM方法區(qū)或者說元空間,類中的原始字符串常量就存在于String Pool中,運(yùn)行時(shí)只有棧中拉取相關(guān)方法時(shí),棧中字符串變量才會依據(jù)String Pool來判斷最終指向堆內(nèi)存String字面量,這種指向才有意義。

前提三:字符串的+相加的不同情況區(qū)分。

  • 形如String combo1 = str1 + str2;這種語句是引用變量(指向堆)與引用變量(指向堆)相加,結(jié)果必然是new String新開辟一個(gè)String堆內(nèi)存。
  • 形如String combo2 = "a" + "bc";這種語句是棧中直接執(zhí)行,結(jié)果得到一個(gè)棧中字符串變量,這時(shí)候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
    }
}
博客引用。本篇文章化用了兩篇博客,代碼將他們匯總使結(jié)論更加明晰。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容