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
因此updateListByAddElement
方法会更改它们共同指向的堆空间中的对象。而updateListByNewList
方法将在方法内部建立的引用变量指向了一份新开辟的堆空间,故对方法外的引用变量所指向的引用变量指向的堆空间中的对象没有修改。get
参考资料:it