通過一段代碼來引入今天的主題:猜一下下面這段代碼的執行結果是什麼?
public class Test {
public static void swap1(int a,int b){
int temp=a;
a=b;
b=temp;
System.out.println("函數中:a:"+a+" b:"+b);
}
public static void main(String[] args) {
int a=10;
int b=20;
swap1(a,b);
System.out.println("主方法:a:"+a+" b:"+b);
}
}
結果爲:
發現兩個變量經過一個函數調用交換之後,他們的值並沒有發生改變,通過這段代碼,我們認爲只是把這兩個變量(實參)拷貝了一份傳遞到函數中的形參中,並沒有改變這兩個變量原本的值;這種方式是值傳遞;
但是觀察下面這段代碼,會發現:
public class ParamTest {
public static void swap2(int[] array){
int temp=array[0];
array[0]=array[1];
array[1]=temp;
System.out.print("函數中:");
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
public static void main(String[] args) {
int[] array=new int[]{1,2};
swap2(array);
System.out.print("主方法中:");
for(int i=0;i<array.length;i++){
System.out.print(array[i]+" ");
}
}
}
結果爲:
經過函數調用後,原始值竟然發生了改變,如果Java傳參是值傳遞的話,那經過函數調用之後,他們的值不是應該沒發生改變嗎?這是爲什麼呢?Java傳參不是值傳遞嗎?爲什麼會產生和上面不一樣的結果呢?
首先,我們要搞清楚值傳遞和引用傳遞的根本含義:
值傳遞:是指在調用函數時,把實際參數的值拷貝一份傳遞給形式參數;在函數調用時,是對形參進行一系類操作,改變的是形參的值,實參的值並不會發生改變;
引用傳遞:是指在調用函數時,將實際參數的地址傳遞給形式參數;在函數調用中,如果該地址的指向發生了變化,則實參的引用指向的值也會發生變化;
Java中數據的存儲:
基本數據類型(八大基本數據類型)是存儲在棧內存中;
引用數據類型(如數組、對象)是存儲在棧內存中,而引用的對象的屬性值是存儲在堆內存中;使用new關鍵字創建出來的類型都是引用數據類型;
基本數據類型:
比如:int a=10;將a的值直接存儲在棧中;
引用對象類型:
int[] array=new int[]{1,2};將array數組的地址存放在棧中,然後根據該地址去堆中查找該數組的值;
而Java中函數傳參,確實是值傳遞,這個值傳遞,傳遞的是棧內存中的值;
對於基本數據類型,函數調用時:
將棧中的值(實參的值)複製了一份,賦值給形參,在函數中做的一系列變化,都是針對形參,並不影響實參的值;
對於引用數據類型,函數調用時:
也是將棧中的值(即地址,因爲引用類型的地址是存放在棧中的)複製了一份,賦值給形參,所以形參和實參的地址是一樣的,他們指向的是堆中的同一段內存,所以當在函數中,對形參進行一系列操作(比如重新賦值)時,如果形參指向的內存的內容發生了變化,則實參指向的內容也會發生變化(因爲形參和實參的地址一樣,它們指向堆中同一段內存);
所以,Java中函數調用時是值傳遞,只是傳遞的值是棧中的值,對於基本數據類型,棧中存儲的值就是變量額值;而對於引用數據類型,棧中存儲的值是該引用變量的地址;