從一道沒人能答對的面試題聊聊Java的值傳遞

小熊我不要了發表於2019-08-22

這是一道我們公司的面試題,從招第二個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出來的物件。

  • 常量池

存放字串常量和基本型別常量。

值傳遞和引用傳遞:

  1. 需要明確一點Java中只有值傳遞。
  2. 值傳遞和引用傳遞,不是傳遞的內容是值是值傳遞,傳遞的是引用就是引用傳遞;也不是傳遞的引數是普通型別就是值傳遞,是物件就是引用傳遞。

拿第三個題目進行分析。先看看在程式執行時堆疊中都發生了些什麼。

如上圖所示。

  • 第一步在棧中存放引用s,並且在堆中開闢空間存放物件並且值為0
  • 第二步呼叫方法會在棧中再宣告一個引用s2,並且指向第一步中物件地址;
  • 第三步中修改s2的值,實際上會在堆中再開闢一個新空間,並且s2指向新的地址。

從上圖中可以看出,s的指向並沒有發生變化,因此第三題得出的答案為0。

繼續看第二題,第二題與第三題的區別在於,Integer的值會放在常量池中,因此將上圖中的堆改為常量池其他的完全一樣,所以第二題的答案也是0。

對於第一題,由於涉及到的形參和實參都是基本型別,因此ii2完全是在棧中操作,此時列印出的結果依舊是0。

相關文章