Java:值傳遞or引用傳遞

前幾天在一套面試題中遇到了一道關於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
	}
}
內存中的情況爲:

情況三:String類。String類也是一個引用類,但是它與別的引用類的區別在於,String類是一個不可變類,在定義時使用了final修飾。如果要對String類型進行改變,那麼就會新建一個String類,所以也不會改變原變量的值。舉例如下:

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
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章