Java的參數傳遞方式
在編程中,往方法中傳遞參數的方法往往有兩種,一種是值傳遞,一種是引用傳遞,而在java中,所有的參數傳遞全部都是值傳遞。但是實際使用中往往會出現一些類似引用傳遞的方式,下面我將一一舉例說明。
首先,java中的所有的對象都是通過“引用”操作的。
java中有五個不同的地方可以儲存對象。
1)寄存器:這是最快的儲存區域,但是這個區域並不能由用戶直接控制,用戶也感覺不到寄存器的存在。
2)堆棧:位於通用RAM中,通過堆棧指針可以獲得直接支持。Java的對象引用及儲存在堆棧之中,但是java對象並不儲存在堆棧中。
3)堆:一種通用的內存池,也存在於RAM中,用於存放所有的java對象,通過new關鍵字創建的對象都會存在於堆中。
4)常量儲存:常量值通常直接存在於程序代碼內部,並存放在ROM(只讀存儲器)中。
5)非RAM儲存:存活於程序之外的數據。
1.傳遞基本類型數據。
java中的基本類型數據即 int,char這一類。測試代碼如下:
1 package com.csust.wk; 2 public class FunctionTest1 { 3 public static void change(int b){ 4 b = 10; 5 } 6 7 public static void main(String[] args) { 8 int i = 5; 9 System.out.println(i); 10 change(i); 11 System.out.println(i); 12 } 13 }
程序輸出:
5
5
由結果可見,傳入change()方法中的變量並沒有被改變。
結果分析:
在基本類型int創建的過程中,如int a = 5; java首先會在堆棧中(所有基本類型的創建和保存都是在堆棧中進行的操作)查詢有沒有5這個值,如果沒有則會在堆棧中開辟一個新的內存空間同時將5置入該空間。然后a這個引用就指向了5所在的內存空間。
這么看的話,將a傳入change()方法之中后,形參b指向了main函數中的實參a的地址(此處也是值傳遞,因為java 復制了一份實參a 的地址然后將其賦給b),對b進行b=10的操作時,java則按照以上的規則進行操作,由於a,b並不是同一個引用,所以當b的引用地址改變成10以后,a所指向的依舊是5所在的地址,這樣就可以得到以上的輸出結果了。另附基礎對象
public static void main(String[] args) {
/*
* 基礎對象測試代碼2
*/
int a = 5;
int b = a;
b = 10;
System.out.println(a);
System.out.println(b);
}
2.數組數據傳遞
測試代碼:
package com.csust.wk; public class FunctionTest1 { public static void change(int[] arg){ arg[0] = 10; } public static void main(String[] args) { int[] arg = {1,2,3,4,5,6}; System.out.println(arg[0]); change(arg); System.out.println(arg[0]); } }
程序輸出:
1
10
結果可見:傳入的arg數組中的值被改變了,arg[0]由1變成了10。
結果分析:
數組實際上結構是保存了一系列的引用,arg[0]是一個指向數組中第一個int儲存空間的引用。而arg則是指向了該數組的引用。
當arg被傳入change()方法時,復制了一個arg的引用,但是該arg也是只想實參arg的地址的,所以對arg[0]進行操作時實際上也是對元數組進行了賦值操作,當回到main函數時,調用的依舊是change()中操作的地址,所以第二次輸出會變成 10 。
3.對象傳遞
測試代碼:
package com.csust.wk; class TestClass { int a; } public class FunctionTest1 { public static void change(TestClass c){ c.a = 10; } public static void main(String[] args) { TestClass cla = new TestClass(); cla.a = 5; System.out.println(cla.a); change(cla); System.out.println(cla.a); } }
結果:
5
10
結果分析:cla中的a變量被改變,結果輸出為10。
類是保存在由jvm分配內存保存在堆中的,當類的引用被傳遞到方法中后,該方法中對該類內的操作都是通過堆內存來操作的,所以會生效。
不會生效的是如下方式:
package com.csust.wk; class TestClass { int a; } public class FunctionTest1 { public static void change(TestClass c){ /*不會生效的方式*/ c = new TestClass(); c.a = 10; } public static void main(String[] args) { TestClass cla = new TestClass(); cla.a = 5; System.out.println(cla.a); change(cla); System.out.println(cla.a); } }
由於值傳遞傳遞的是引用的復制,當將方法中的c引用重新定位到新的類(即不同的內存地址)的時候,對新的類的操作是不會影響到原類的,也就是說,java的值傳遞的意思是,傳遞的過程中可以對原引用造成一定的影響,可以改變引用對象中的數據,但是不可以直接操作到該引用,因為java傳遞過去的不是一個指向源引用的指針,而是原引用的一個復制,這個值傳遞的概念是成立的,只是由於java對於值傳遞的特殊處理方式所以導致有的人對該值傳遞產生一定的質疑。
