String是值傳遞還是引用傳遞

String中的坑

  最近看到一道關於String的面試題,差點讓我以爲String是值傳遞,就是下面這個例子,體驗下:<!-- more -->

public class Demo{
    public static void main(String[] args) {
        Demo d = new Demo();
        String str = "BEA";
        d.change(str);
        System.out.println(str);
    }
    void change(String s){
        s= s.replace('A', 'E');
        s = s.toLowerCase();
    }
}

  當時一看到這個題目,我第一反應就是輸出”bee“,因爲String是引用類型,其參數傳遞的方式就是引用傳遞,傳遞的是String的地址。可是答案讓我的大吃一驚,“BEA”,str根本就沒有發生變化!!

  難道String是值傳遞?難道String是基本類型?

  其實都不是,後來通過查閱相應資料發現,jvm在實例化字符串時會使用字符串常量池,把str作爲參數傳入change()方法。jvm複製了一份str變量,爲了便於理解我們叫它str'。這個時候str和str'都指向字符串常量池中的“abc”。

  當我們執行s = s.replace('A', 'E');
其實相當於執行了s = new String(s.replace('A', 'E'));

 要理解上面這兩段話,就要從java的底層結構說起了。java的內存模型大體分爲 (細分還有方法區,和程序計數器等)。

1.基本類型的變量放在棧裏;

2.封裝類型中,對象放在堆裏,對象的引用放在棧裏。

<font color=red>java在方法傳遞參數時,是將變量複製一份,然後傳入方法體去執行。</font>

根據這些再細分一下jvm的執行過程

1.虛擬機在堆中開闢一塊內存,並存值”BEA”。

2.虛擬機在棧中分配給str一個內存,內存中存的是1中的地址。(1指第一步)

3.虛擬機複製一份str,我們叫str’,str和str’內存不同,但存的值都是1的地址。

4.將str’傳入方法體

5.方法體在堆中開闢一塊內存,並存值”BEE”。

6.方法體在堆中再次開闢一塊內存,並存值”bee”。

7.方法體將str’的值改變,存入5的內存地址。

8.方法結束,方法外打印str,由於str存的是1的地址,所有打印結果是”BEA”。

 String的底層是一個不可變數據,所以每次給他賦新的值的時候都相當於新建了一個String對象(如果String常量池裏沒有該字符串的話),我們可以驗證一下。
public class Demo{
    public static void main(String[] args) {
        Demo d = new Demo();
        //通過比較str的hashCode來比較兩個對象是否爲同一對象
        String str = "BEA";
        System.out.println("第一次String的hashCode:"+str.hashCode());
        str = "bee";
        System.out.println("第二次String的hashCode:"+str.hashCode());
        //StringBuilder來試一次
        StringBuilder s = new StringBuilder("BEA");
        System.out.println("第一次StringBuilder的hashCode:"+s.hashCode());
        s.append('T');
        System.out.println("第二次StringBuilder的hashCode:"+s.hashCode());
        System.out.println("調用方法前的StringBuilder對象的值:"+s);
        d.change(s);
        System.out.println("調用方法後的StringBuilder對象的值:"+s);
    }
    void change(StringBuilder s){
        s = s.append('S');
    }
}

  看看執行的結果~

file

tips: hashcode並不能判斷是否爲同一個對象,但是hashcode不同的話肯定不是同一個對象,hashcode相同的不一定是同一個對象。

file

關注我不會讓你失望喲~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章