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

相关文章
相关标签/搜索