當一個對象被當作參數傳遞到一個方法后,在此方法內可以改變這個對象的屬性,那么這里到底是「按值傳遞」還是「按引用傳遞」?
答:是按值傳遞。Java 語言的參數傳遞只有「按值傳遞」。當一個實例對象作為參數被傳遞到方法中時,參數的值就是該對象的引用的一個副本。指向同一個對象,對象的內容可以在被調用的方法內改變,但對象的引用(不是引用的副本) 是永遠不會改變的。
Java 的參數傳遞,不管是基本數據類型還是引用類型的參數,都是按值傳遞,沒有按引用傳遞!
我們可以看一下 microsoft 的 C# 文檔中對按引用傳遞參數的定義(如下截圖):
1、基本數據類型的參數
先來看一下基本數據類型的參數按值傳遞的例子:
TransferTest.java
public class TransferTest { public static void main(String[] args) { int num = 1; System.out.println("changeNum()方法調用之前:num = " + num); changeNum(num); System.out.println("changeNum()方法調用之后:num = " + num); } public static void changeNum(int x) { x = 2; } }
運行結果:
這個傳遞過程的示意圖如下:
num作為參數傳遞給changeNum()方法時,是將內存空間中num所指向的那個存儲單元中存放的值1傳遞給了changeNum()方法中的x變量,而這個x變量也在內存空間中分配了一個存儲單元,這個時候,就把num的值1傳遞給了x的這個存儲單元中。此后,在changeNum()方法中對x的一切操作都是針對x所指向的這個存儲單元,與num所指向的那個存儲單元沒有關系了!
所以,在changeNum()方法調用之后,num所指向的存儲單元的值還是沒有發生變化,這就是所謂的“按值傳遞”!按值傳遞的精髓是:傳遞的是存儲單元中的內容,而不是存儲單元的引用!
2、引用類型的參數
同樣,先看一個例子:
TransferTest2.java
1 public class TransferTest2 { 2 public static void main(String[] args) { 3 Person p1 = new Person(); 4 System.out.println(p1); 5 change(p1); 6 System.out.println(p1); 7 } 8 9 public static void change(Person p2) { 10 p2 = new Person(); 11 } 12 } 13 14 /** 15 * Person類 16 */ 17 class Person { 18 19 }
運行結果:
可以看出兩次打印person的地址值是一樣的,即調用完change() 方法之后,person變量並沒有發生改變。
這個傳遞過程的示意圖如下:
當執行到第3行代碼時,程序在堆內存中開辟了一塊內存空間用來存儲Person類的實例對象,同時在棧內存中開辟了一個存儲單元用來存儲該實例對象的引用,即上圖中person指向的存儲單元。
當執行到第5行代碼時,person作為參數傳遞給change()方法,需要注意的是:person將自己存儲單元的內容傳遞給了change()方法的p變量!此后,在change()方法中對p的一切操作都是針對p所指向的存儲單元,與person所指向的那個存儲單元沒有關系了!
本文永久更新地址:https://github.com/nnngu/LearningNotes/blob/master/Java%20Basis/007%20Java%E7%9A%84%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92%E6%98%AF%E5%80%BC%E4%BC%A0%E9%80%92%E8%BF%98%E6%98%AF%E5%BC%95%E7%94%A8%E4%BC%A0%E9%80%92.md