這是一道我們公司的面試題,從招第二個Java以來就一直存在了。但是面試了這么長的時間還沒有一個人可以全部答對,讓我們一度以為是這題出的不對。首先請看面試題。
以下運算的輸出分別是多少:
public static void main(String[] args) {
int i = 0;
change(i);
System.out.println(i);
}
private static void change(int i2) {
i2 = 1;
}
public static void main(String[] args) {
Integer i = 0;
change(i);
System.out.println(i);
}
private static void change(Integer i2) {
i2 = 1;
}
public static void main(String[] args) {
StringBuilder s = new StringBuilder("0");
change(s);
System.out.println(s);
}
private static void change(StringBuilder s2) {
s2 = new StringBuilder("1");
}
看完題之后你是不是已經有了自己的答案,記下你的答案,不介意的話評論區留言看看有沒有人能全對。
首先需要明確幾個概念。
實參與形參:
如下圖所示,形式參數是在定義函數名和函數體的時候使用的參數,目的是接收調用該函數時傳入的參數。
實際參數是在調用有參函數時傳入的參數。
堆和棧:
-
棧
存放基本類型的變量數據和對象的引用,但對象本身不存放在棧中,而是存放在堆(new 出來的對象)或者常量池中(字符串常量對象存放在常量池中。)
-
堆
存放所有new出來的對象。
-
常量池
存放字符串常量和基本類型常量。
值傳遞和引用傳遞:
-
需要明確一點Java中只有值傳遞。
-
值傳遞和引用傳遞,不是傳遞的內容是值是值傳遞,傳遞的是引用就是引用傳遞;也不是傳遞的參數是普通類型就是值傳遞,是對象就是引用傳遞。
拿第三個題目進行分析。先看看在程序運行時堆棧中都發生了些什么。
如上圖所示。
- 第一步在棧中存放引用
s
,並且在堆中開辟空間存放對象並且值為0
; - 第二步調用方法會在棧中再聲明一個引用
s2
,並且指向第一步中對象地址; - 第三步中修改s2的值,實際上會在堆中再開辟一個新空間,並且
s2
指向新的地址。
從上圖中可以看出,s
的指向並沒有發生變化,因此第三題得出的答案為0。
繼續看第二題,第二題與第三題的區別在於,Integer
的值會放在常量池中,因此將上圖中的堆改為常量池其他的完全一樣,所以第二題的答案也是0。
對於第一題,由於涉及到的形參和實參都是基本類型,因此i
和i2
完全是在棧中操作,此時打印出的結果依舊是0。
轉評贊就是最大的鼓勵