天天看點

Java工程師面試1000題144-方法參數的傳遞機制

144、看下面程式的執行結果

import java.util.Arrays;

public class Exam4 {
    public static void main(String[] args) {
        int i = 1;
        String str = "hello";
        Integer num = 200;
        int[] arr = {1,2,3,4,5};
        MyData my = new MyData();

        change(i,str,num,arr,my);

        System.out.println("i = " + i);
        System.out.println("str = " + str);
        System.out.println("num = " + num);
        System.out.println("arr = " + Arrays.toString(arr));
        System.out.println("my.a = " + my.a);
    }
    public static void change(int j, String s, Integer n, int[] a, MyData m){
        j += 1;
        s += "world";
        n += 1;
        a[0] += 1;
        m.a += 1;
    }
}
class MyData{
    int a = 10;
}
           

答案:

i = 1
str = hello
num = 200
arr = [2, 2, 3, 4, 5]
my.a = 11
           

解析:本題主要考察了方法的傳遞機制和String、包裝類等對象的不可變性。

首先我們先分析一下執行完下面五行代碼之後,記憶體的存儲情況是什麼樣子的。

int i = 1;
String str = "hello";
Integer num = 200;
int[] arr = {1,2,3,4,5};
MyData my = new MyData();
           

為便于了解,下面我畫一個簡單的示意圖:

Java工程師面試1000題144-方法參數的傳遞機制

i是一個int類型的,又是一個局部變量,直接存儲在棧裡面;str是一個引用資料類型的資料,指向的是“hello”字元串常量,字元串常量是存儲在常量池裡面,str存儲的是一個記憶體位址,我們随便寫一個值吧0x1234;Integer是一個包裝類,是以num也是存儲的記憶體位址,指向的是堆當中的一塊記憶體區域;arr是一個數組,數組名裡面存儲的是首位址,數組的本體也是存儲在堆中,arr中存放也是一個記憶體位址;MyData也是一個對象,my指向的是對象在堆裡面的記憶體位址。

接下來,程式要開始執行  change(i,str,num,arr,my);了,執行change的時候,JVM也會給change開辟一塊記憶體空間,change方法裡面有五個參數,是以這裡又會有産生局部變量了,方法的參數傳遞機制告訴我們:形參是基本資料類型時,傳遞的是資料值。形參是引用資料類型,傳遞的是位址值。特殊類型:String、包裝類等對象具有不可變性。每一個方法,建立一個棧幀,棧幀存放了目前就方法的資料資訊(局部變量),當方法調用完畢,該方法的棧幀就被銷毀。參數傳遞完成之後,記憶體中的情況會變成下面的樣子:

Java工程師面試1000題144-方法參數的傳遞機制

接下來進行下一步操作,執行方法體裡面的内容。

j += 1;
s += "world";
n += 1;
a[0] += 1;
m.a += 1;
           

第一句:j += 1;是以我們要在j變量上進行修改,變為2. 

再看下一句,形參s此時也指向常量池裡面的hello,要執行拼接操作,此時會在常量池中産生一個新的對象,就是拼接之後的對象,helloworld,然後再把它指派給s,是以,此時s不再指向常量池中hello的記憶體位址了,轉而指向helloworld所在的記憶體位址了,不再是0x1234了。

以此類推,包裝類型n也不再指向200所在的堆記憶體位址0x9090了,轉而指向加一之後201的記憶體位址。

數組是怎麼發生變化的呢?由于我們這個例子改變的是元素,通過位址0x8989找到a[0]所在的位置,然後就把a[0]的1改變為了2,後面的幾個數字不變。

同樣的,我們通過m 0x7878一樣可以找到堆中的int a = 10,改變a 的值為11.

每一個方法,建立一個棧幀,棧幀存放了目前就方法的資料資訊(局部變量),當方法調用完畢,該方法的棧幀就被銷毀。

是以當我們吧change方法執行完之後,就變成了下面的樣子,棧幀被銷毀了:

Java工程師面試1000題144-方法參數的傳遞機制

由此可見,在堆中有兩處的值發生了改變,一個數數組的第一個元素變為了2,一個是MyData的int a = 11.

主方法剩下的,i沒有改變,仍然還是1,String str 指向的依舊是hello,num指向的依舊是200所在的位址,arr[0]變為了2,MyData.a變為了11.是以程式執行結果就是下面的了:

i = 1
str = hello
num = 200
arr = [2, 2, 3, 4, 5]
my.a = 11