前幾天在一套面試題中遇到了一道關於Java的參數傳遞方式的問題,當時沒有回答正確。後來在查閱資料後對這個問題有了詳細的瞭解,在此記錄一下。
在給類編程語言中,參數傳遞的方式有兩種。一種是值傳遞,另一種是引用傳遞。首先來明確一下兩種傳遞方式具體是什麼意思。
值傳遞是指在方法調用時,傳遞給方法的參數,實際上是將原來的變量複製一份之後,將複製品傳遞給了被調用的方法。因爲被調用方法得到的是原變量的一個拷貝,所以無論這個方法怎麼修改參數,都不會改變原變量的值。
而引用傳遞是指在方法調用時,是將原變量的引用,也就是變量在內存中的地址空間,傳給了被調用方法。因此,被調用方法中的參數和原變量指向的是同一段內存空間。當被調用方法修改參數所指的內存空間內部的值時,原變量的值也會改變。
對於Java的參數傳遞方式,有兩種說法,有人說Java只有值傳遞,有人說Java既有值傳遞,又有引用傳遞。其實Java的傳遞方式到底叫什麼並不重要,重要的是瞭解在不同的條件下,Java進行參數傳遞時,內存中到底發生了什麼樣的變化。
參數傳遞時內存的改變情況與所傳遞參數的類型有關。我們知道Java有兩類變量類型:基本類型,比如int,float,double等;引用類型:比如數組,String,ArrayList等。這兩類數據類型,在內存分配上的區別在於:基本類型的變量名所指向的內存中,存儲的就是變量本身的值;而引用類型的變量名所指向的內存中,存儲的是一個內存地址,這個內存地址內存儲的纔是引用類型本身。
對於基本類型,Java就是講原類型複製一份,將拷貝傳遞給被調用函數。舉例如下:
public class MyTest {
public static void change(int b) {
b = 6;
}
public static void main(String[] args) {
int a = 5;
change(a);
System.out.println("a=" + a);// 輸出a=5
}
}
可見,我們在change()方法中對b進行了重新複製,但並沒有影響a的值。兩者在內存中的分配方式如下:
對於引用類類型,可以確定的是Java是將其在內存中的地址傳遞給了被調用方法。但是,當方法對參數進行改變時,是否會修改原參數則需要分情況討論。
情況一:直接修改參數內部的值,這時,修改會改變原變量的值:
public class MyTest {
public static void change(int[] b) {
for(int i = 0; i<b.length; i++){
b[i] = b[i] * 2;
}
}
public static void main(String[] args) {
int[] a = new int[]{1,2,3};
change(a);
for(int i = 0; i<a.length; i++){
System.out.print(a[i] + " ");
}
// 輸出結果爲2 4 6
}
}
內存中的情況爲:
public class MyTest {
public static void change(int[] b) {
b = new int[]{2,4,6};
}
public static void main(String[] args) {
int[] a = new int[]{1,2,3};
change(a);
for(int i = 0; i<a.length; i++){
System.out.print(a[i] + " ");
}
// 輸出結果爲1 2 3
}
}
內存中的情況爲:public class MyTest {
public static void change(String b) {
b += "cde";
}
public static void main(String[] args) {
String s = "abc";
change(s);
System.out.println(s);
// 輸出結果爲abc
}
}
public class MyTest {
public static void change(String b) {
b = new String("cde");
}
public static void main(String[] args) {
String s = "abc";
change(s);
System.out.println(s);
// 輸出結果爲abc
}
}