java String創(chuàng)建字符串對(duì)象——面試java基礎(chǔ)

在一次面試中,被問(wèn)到這方面的問(wèn)題,搞得我一臉蒙逼,那時(shí)候還沒(méi)去了解JVM,為了以后不再出現(xiàn)這樣的情況,我就在這里好好梳理一下String創(chuàng)建會(huì)創(chuàng)建多少個(gè)對(duì)象呢?

先看代碼

public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "a" + "b" + "c";
        System.out.println("結(jié)果1:" + (str1 == str2));
        String str3 = "a";
        String str4 = str3 + "bc";
        System.out.println("結(jié)果2:" + (str1 == str4));
        System.out.println("結(jié)果3:" + (str1 == str4.intern()));
        final String str5 = "a";
        String str6 = str5 + "bc";
        System.out.println("結(jié)果4:" + (str1 == str6));
    }

代碼運(yùn)行結(jié)果:

結(jié)果1:true
結(jié)果2:false
結(jié)果3:true
結(jié)果4:true

上面的運(yùn)行結(jié)果需要從兩個(gè)方面來(lái)說(shuō)明:
一:java編譯器
二:java字符串常量池

java編譯器

我們來(lái)看看java編譯器將上面的源碼編譯成了什么樣子。(反編譯結(jié)果)

public static void main(String[] args) {
        String str1 = "abc";
        String str2 = "abc";
        System.out.println("結(jié)果1:" + (str1 == str2));
        String str3 = "a";
        String str4 = str3 + "bc";
        System.out.println("結(jié)果2:" + (str1 == str4));
        System.out.println("結(jié)果3:" + (str1 == str4.intern()));
        String str5 = "a";
        String str6 = "abc";
        System.out.println("結(jié)果4:" + (str1 == str6));
    }

源代碼和編譯后的代碼有很多不同點(diǎn)。str2和str6都變成了直接賦值為"abc",而str4卻沒(méi)有變化,這里也是java新手不太清楚的地方,其實(shí)由于常量字符串是在編譯的時(shí)候就是可以被確定的,又因"a","b"和"c"都是字符串常量,因此變量str2的值在編譯時(shí)就可以確定,同理因?yàn)閟tr5被final關(guān)鍵字修飾,也相當(dāng)于字符串常量,因此變量str6的值也在編譯時(shí)就可以確定,代碼編譯后就和String str="abc"一樣了。
也是因?yàn)樯厦娴脑騭tr4沒(méi)有改變,因?yàn)閟tr4并不能在編譯期確定。

java字符串常量池

在執(zhí)行代碼String str1 = "abc"時(shí),JVM先去字符串常量池中查找,看是否已經(jīng)存在值為”abc”的對(duì)象,如果存在,則不再創(chuàng)建新的對(duì)象,而直接返回已存在對(duì)象的引用;反之,則先創(chuàng)建一個(gè)新的對(duì)象,然后加入到字符串池中,再將其引用返回。

String str1 = "abc";  // 會(huì)創(chuàng)建一個(gè)新的對(duì)象"abc"在字符串常量池中
String str2 = "abc";  // 因?yàn)樽址A砍刂幸呀?jīng)存在"abc",所以不會(huì)創(chuàng)建對(duì)象

這樣結(jié)果1true,就可以理解了

String str3 = "a";  // 會(huì)創(chuàng)建一個(gè)新的對(duì)象"abc"在字符串常量池中
/* 
下面這行代碼一共會(huì)創(chuàng)建三個(gè)對(duì)象:
  1. 會(huì)在字符串常量池中創(chuàng)建一個(gè)"bc"對(duì)象
  2. str3與 "bc" 進(jìn)行字符串連接時(shí),底層通過(guò)StringBuffer進(jìn)行連接,生成一個(gè)
    StringBuffer對(duì)象(StringBuffer內(nèi)部字符不考慮)
  3. 然后通過(guò)StringBuffer的append方法連接,通過(guò)toString()方法,將StringBuffer對(duì)象
    轉(zhuǎn)為String,此時(shí)會(huì)產(chǎn)生一個(gè)新的堆內(nèi)存地址,str4指向這個(gè)新的內(nèi)存地址。
*/
String str4 = str3 + "bc"; 
// 因?yàn)閟tr4在堆內(nèi)存變量中,str1在字符串常量池中,所以==地址比較為false
System.out.println("結(jié)果2:" + (str1 == str4));
// str4.intern() 返回在字符串常量池中的"abc"引用,就和str1是同一對(duì)象,為true
System.out.println("結(jié)果3:" + (str1 == str4.intern()));

字符串相加推薦文章

看完上面的代碼相信您已經(jīng)對(duì)字符串創(chuàng)建對(duì)象個(gè)數(shù)有了一定的了解,接下來(lái)我們?cè)賮?lái)看看另一種情況。

/*
下面的代碼,一共會(huì)創(chuàng)建兩個(gè)對(duì)象:
  1. 在字符串常量池中創(chuàng)建"abc"對(duì)象
  2. 在堆中創(chuàng)建的原實(shí)例字符串對(duì)象
*/
String str1 = new String("abc");
// str1只是java棧中的對(duì)象引用

注意:String類(lèi)型的引用是存在棧里。而字符串"abc"是存在字符串常量池中

// 在字符串常量池中創(chuàng)建一個(gè)"abc"對(duì)象
String str1 = "abc";
// 由于"abc"已經(jīng)在字符串常量池中已經(jīng)存在,所以不會(huì)再創(chuàng)建。
// 使用new關(guān)鍵字創(chuàng)建字符串,一定會(huì)在堆中創(chuàng)建一個(gè)實(shí)例,所以下面代碼會(huì)創(chuàng)建一個(gè)對(duì)象
String str2 = new String("abc");
// str1只是java棧中的對(duì)象引用

注意:String類(lèi)型的引用是存在棧里。而字符串"abc"是存在字符串常量池中

下面提升難度

  public static void main(String[] args) {
        String str1 = "a" + new String("b");
        String str2 = "ab";
        System.out.println(str1 == str2);
        String str3 = str2 + "c";
        str3.intern();
        String str4 = "abc";
        System.out.println(str3 == str4);
    }

運(yùn)行結(jié)果:

false
true

注意:上面的運(yùn)行結(jié)果和jdk版本有關(guān),1.7和1.8都是上面的結(jié)果,1.7以下不是
上面的結(jié)果重點(diǎn)就是intern方法的作用,這里我只是拋磚引玉,想了解更多的讀者可以看看下面的這篇博客:
深入解析String#intern

筆者個(gè)人能力有限,如有錯(cuò)誤,請(qǐng)聯(lián)系我修改。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從網(wǎng)上復(fù)制的,看別人的比較全面,自己搬過(guò)來(lái),方便以后查找。原鏈接:https://www.cnblogs.com/...
    lxtyp閱讀 1,436評(píng)論 0 9
  • 前言 RTFSC (Read the fucking source code )才是生活中最重要的。我們天天就是要...
    二毛_coder閱讀 524評(píng)論 1 1
  • 注:都是在百度搜索整理的答案,如有侵權(quán)和錯(cuò)誤,希告知更改。 一、哪些情況下的對(duì)象會(huì)被垃圾回收機(jī)制處理掉 ?當(dāng)對(duì)象對(duì)...
    Jenchar閱讀 3,311評(píng)論 3 2
  • 本文是我自己在秋招復(fù)習(xí)時(shí)的讀書(shū)筆記,整理的知識(shí)點(diǎn),也是為了防止忘記,尊重勞動(dòng)成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 959評(píng)論 1 6
  • 在編寫(xiě)程序的過(guò)程中,不了避免的要用到字符串,所以String類(lèi)的常用方法的用法是必須掌握的。學(xué)習(xí)一個(gè)類(lèi)的使用方法最...
    Geg_Wuz閱讀 1,497評(píng)論 0 4

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