前段時間參加了一場面試,其中有一道引用傳遞的題,由於當時並無考慮清楚因此作錯了。
如今來複盤一下,題目以下:html
private static void change(StringBuffer str11, StringBuffer str12) {
str12 = str11;
str11 = new StringBuffer("new world");
str12.append("new world");
}
public static void main(String[] args) {
StringBuffer str1 = new StringBuffer("good ");
StringBuffer str2 = new StringBuffer("bad ");
change(str1, str2);
System.out.println(str1.toString());
System.out.println(str2.toString());
}
good new world
badweb
下面就來複盤一下爲什麼是這兩個答案,下面會作詳細的圖文分析。
要搞明白這個問題,那麼就須要明白Java中的值傳遞和引用傳遞了。面試
Java對象參數傳遞雖然傳遞的是地址(引用),但仍然是值調用。是時候須要給引用調用和值調用一個準確的定義了。編程
值調用(call by value): 在參數傳遞過程當中,形參和實參佔用了兩個徹底不一樣的內存空間。形參所存儲的內容是實參存儲內容的一份拷貝。實際上,Java對象的傳遞就符合這個定義,只不過形參和實參所儲存的內容並非常規意義上的變量值,而是變量的地址。咳,回過頭想一想:變量的地址不也是一種值嗎!app
引用調用(call by reference) : 在參數傳遞的過程當中,形參和實參徹底是同一塊內存空間,二者不分彼此。 實際上,形參名和實參名只是編程中的不一樣符號,在程序運行過程當中,內存中存儲的空間纔是最重要的。不一樣的變量名並不能說明佔用的內存存儲空間不一樣。ide
那麼接下來就畫圖分析文章開頭拋出的問題:
這裏再把代碼貼一遍,你們能夠對比着代碼和圖一塊兒看。函數
private static void change(StringBuffer str11, StringBuffer str12) {
str12 = str11;//2
str11 = new StringBuffer("new world");//3
str12.append("new world");//4
}//5
public static void main(String[] args) {
StringBuffer str1 = new StringBuffer("good ");
StringBuffer str2 = new StringBuffer("bad ");
change(str1, str2);//1
System.out.println(str1.toString());
System.out.println(str2.toString());
}
執行到第一步的圖:
spa
執行到第二步的圖,這裏chage方法中的形參str11,str22是實參str1,str2的地址拷貝。
orm
這裏str11和str22是實參str1,str2的地址拷貝,接着執行第三步的圖:
htm
上圖中str12地址指向了「good」,接着看第四步圖:
上圖中str11的地址指向了堆中新的對象"new world",接着看第五步的圖:
這裏圖算是畫完了,確實不太擅長畫圖,你們就先勉強看吧。
這裏有一個很重要的點就是StringBuffer是可變的,具體解釋你們能夠搜索下。
由於這裏str12.append("new world")直接修改了good的值。因此main函數中打印的會是:good new world。
到這裏就算講完了,一個很簡單的例子,這裏算是對以前一道筆試題的覆盤,有不對的地方歡迎你們指正。