Java究竟是值傳遞仍是引用傳遞?

Java的傳遞不少人都知道是值傳遞。但很多人說不出這個值到底指的是什麼?有的時候如基本類型int,long表現的像值。有的時候如List又表現的像傳遞引用。這究竟是怎麼一回事呢?java

值傳遞仍是引用傳遞?

先看兩個例子:spa

public static void updateBasicInt(int a1) {
    a1 = 5;
}

public static void updateListByAddElement(List<Integer> nums1) {
    nums1.add(5);
}

@Test
public void should_not_change_basic_int() {
    int a = 10;
    updateBasicInt(a);
    assertThat(a).isEqualTo(10);
}

@Test
public void should_update_list_when_add_element() {
    List<Integer> nums = new ArrayList<>();
    nums.add(1);
    nums.add(2);
    assertThat(nums.size()).isEqualTo(2);

    PassValueOrRef.updateListByAddElement(nums);

    assertThat(nums.size()).isEqualTo(3);
}

看到這裏有的人可能會說:可變對象傳引用,不可變對象傳值。然而真的是這樣嗎?code

再看一個例子:對象

public static void updateListByNewList(List<Integer> nums1) {
    nums1 = new ArrayList<>();
    nums1.add(5);
}

@Test
public void should_not_update_list_when_new_list() {
    List<Integer> nums = new ArrayList<>();
    nums.add(1);
    nums.add(2);
    assertThat(nums.size()).isEqualTo(2);

    PassValueOrRef.updateListByNewList(nums);

    assertThat(nums.size()).isEqualTo(2);
}

若是真的是可變對象List傳引用,爲何nums仍是看起來沒有被改變?nums的引用明明在updateListByNewList方法中被更改了呀。blog

實際上,Java只有值傳遞一種方式。對於基本類型,基本類型被直接存儲在棧中。當基本類型的參數被傳遞給方法時,拷貝一份實參並存儲在新開闢的棧空間中。 而對於對象引用,引用變量被存儲在棧空間中,而引用變量實際指向的對象被存儲在堆空間中。當一個對象被傳遞給方法時,會拷貝一份引用變量並存儲在新開闢的棧空間中,但引用變量仍只指向以前已經建立的存儲在堆中的對象。element

valueOrRef.png

因此updateListByAddElement方法會更改它們共同指向的堆空間中的對象。而updateListByNewList方法將在方法內部建立的引用變量指向了一份新開闢的堆空間,故對方法外的引用變量所指向的引用變量指向的堆空間中的對象沒有修改。get

參考資料:it

相關文章
相關標籤/搜索