【Java】探究Java方法的参数传递是值传递还是引用传递
測試思路
每個更改形參的方法,返回值都是void,不同方法的參數設置不同類型。
注意在方法內測地址的時候在改之前測一下,才能看出傳入參數是不是傳了地址。(注意反正OS的內存地址是虛擬的,JVM中的也是,掰扯不清的,所以就姑且按照JVM中的虛擬地址來考慮吧)
數組參數傳遞
private static void changeArray(int[] array) {Arrays.fill(array, 2); }數組的值改變了,但地址沒變,是引用傳遞。
基本類型及其包裝類的參數傳遞
private static void changeInt(int data) {data = 3; }private static void changeInteger(Integer data) {data = 3; }無論是int還是Integer,沒有返回值,所以外面的實參值沒變。
對于基本類型,打印地址也能看出地址改了,是值傳遞。
對于包裝類型,打印地址能看出地址沒改,是引用傳遞。
由于hashCode()被重寫了,所以可以用System.out.println(System.identityHashCode(data));來看虛擬地址(當然不是真的地址啦)。
普通類參數傳遞
private static class Person {int id;String name;int age;Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';} }private static void changePerson(Person data) {data = new Person(101, "Bob", 15); }是引用類型,也是引用傳遞。打印地址測試過,確實在new之前的虛擬地址與傳入實參的虛擬地址一致。(想測地址就把@Override的toString()注釋掉,再打印對象啊)
只改屬性
private static void changePersonAttributes(Person data) {data.id = 101;data.name = "Bob";data.age = 15; }改了屬性,打印結果改了,但是實際地址沒改,說明是引用傳遞。
完整代碼
部分打印地址的測試內容就刪掉不附上了,感興趣可以自測。
import java.util.Arrays;public class ReferenceTest {private static void changeArray(int[] array) {Arrays.fill(array, 2);}private static void changeInt(int data) {data = 144;}private static void changeInteger(Integer data) {data = 155;}private static class Person {int id;String name;int age;Person(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}@Overridepublic String toString() {return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';}}private static void changePerson(Person data) {data = new Person(101, "Bob", 15);}private static void changePersonAttributes(Person data) {data.id = 101;data.name = "Bob";data.age = 15;}public static void main(String[] args) {int[] array = new int[5];System.out.println(Arrays.toString(array));changeArray(array);System.out.println(Arrays.toString(array));Integer a = 133;changeInteger(a);System.out.println(a);changeInt(a);System.out.println(a);Person p = new Person(100, "Sam", 10);System.out.println(p);changePerson(p);System.out.println(p);changePersonAttributes(p);System.out.println(p);} }測試結果
[0, 0, 0, 0, 0] [2, 2, 2, 2, 2] 133 133 Person{id=100, name='Sam', age=10} Person{id=100, name='Sam', age=10} Person{id=101, name='Bob', age=15}總結反思
其實自己也一直沒搞明白Java的參數傳遞到底是值傳遞還是引用傳遞,網上說法眾說紛紜,于是下定決心自己認真測一下。
按照JVM的虛擬地址來做測試,在整數測試的時候還考慮了整數緩存池,選了127以上的數。
個人認為,其實不能單純利用返回值為void的函數運行后查看原值來判斷是值傳遞還是引用傳遞。我選擇在傳完參數后的函數內測地址,地址一樣就是引用傳遞,不一樣就是值傳遞。
hashCode()一般包含了地址,但Integer的hashCode()則只是原值,得使用System.identityHashCode(data)來測。
emmm,接下來,講講結論orz
總結
- 基本類型是值傳遞
- 引用類型是引用傳遞,返回值為void的話未必能在外面看到改變。
- 引用類型對象重新被new了以后,看不到改變;但改變屬性能看到改變。
- 數組也是引用類型,數組元素值的改變能在void方法外面測出來。
其實研究這個問題Real迷惑,如有不足還請指正!
Update on 2020.3.7
強調String這個問題,如果你簡單地測試得到地址沒變,這是不對的,涉及到String常量池等等……
因為我還不太會,所以回頭再來補充orz
看來這篇文章可能有些我思慮不周(尚未涉獵)的地方啊,果然水深莫涉啊orz
總結
以上是生活随笔為你收集整理的【Java】探究Java方法的参数传递是值传递还是引用传递的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【操作系统】同步和互斥
- 下一篇: java美元兑换,(Java实现) 美元