前段時間對Java中參數傳遞問題有點困惑,不了解其中的含義。查閱了很多資料,這里談談自己對該問題的理解。
參數傳遞一般有兩種,一種是“傳值”,另一種是“傳地址值”。傳值是指在調用方法時,把參數的值傳遞給方法,而傳地址值則是給方法提供參數的地址值。Java中的參數傳遞方法都為傳值調用。下面我通過例子來驗證。
1.基本類型的參數傳遞
1 public class ParamTransfer { 2 public int money; 3
4 public void amethod(int i) { 5 System.out.println("方法得到的i的值:" + i); 6 i = i * 5; 7 System.out.println("方法執行語句i=i*5后i的值:" + i); 8 System.out.println("money的值:" + this.money); 9 } 10
11 public static void main(String[] args) { 12 ParamTransfer pt = new ParamTransfer(); 13 pt.money = 100; 14 pt.amethod(pt.money); 15 } 16
17 }
運行結果如下:
方法得到的i的值:100 方法執行語句i=i*5后i的值:500 money的值:100
注意對比形參i和money值的變化。這里我們把pt.money作為參數傳遞給amethod方法,該方法中i得到的值是100,這個我們從運行結果中可知。執行完i=i*5語句后我們發現當前對象的money屬性值並沒有發生改變,這就說明這里只是傳了一個100數值給形參i,相當於把pt.money的值拷貝給i,i的變化並不會影響pt.money的值,僅僅是傳數值。
2.引用類型的參數傳遞
1 class Time { 2 public int hour; 3 public int minute; 4 public int second; 5 } 6
7 public class ObjectParamTransfer { 8 Time time; 9
10 public static void main(String[] args) { 11 ObjectParamTransfer opt = new ObjectParamTransfer(); 12 opt.time = new Time(); 13 opt.time.hour = 11; 14 opt.time.minute = 22; 15 opt.time.second = 33; 16
17 System.out.println("time的屬性值:"); 18 System.out.println("hour=" + opt.time.hour); 19 System.out.println("minute=" + opt.time.minute); 20 System.out.println("second=" + opt.time.second); 21
22 opt.method(opt.time);//將對象引用作為參數傳遞給方法method 23 //對比執行方法后的變化
24 System.out.println("執行方法后的time的屬性值"); 25 System.out.println("hour=" + opt.time.hour); 26 System.out.println("minute=" + opt.time.minute); 27 System.out.println("second=" + opt.time.second); 28
29 } 30
31 private void method(Time t) { 32 System.out.println("參數t的屬性值:"); 33 System.out.println("hour=" + t.hour); 34 System.out.println("minute=" + t.minute); 35 System.out.println("second=" + t.second); 36 System.out.println("對t和time進行==比較,結果為:" + (t == this.time)); 37
38 System.out.println("改變t的實例變量值"); 39 t.hour = 44; 40 t.minute = 55; 41 t.second = 60; 42 } 43 }
運行結果如下:
time的屬性值: hour=11 minute=22 second=33 參數t的屬性值: hour=11 minute=22 second=33 對t和time進行==比較,結果為:true 改變t的實例變量值 執行方法后的time的屬性值: hour=44 minute=55 second=60
將對象引用opt.time傳遞給method方法后先輸出參數t的屬性值,發現和原來對象引用的屬性值是相同的。進一步返回t==this.time的結果為true。改變t的實例變量值后,當前引用opt.time的屬性值也隨之發生改變。這就充分證明了參數t和對象引用opt.time指向同一對象,即它們指向的內存空間地址一致。那么問題來了,到底是opt.time這個引用傳遞了內存空間地址值給參數t還是它自己就是這個參數t呢?這我們不得而知。下面再通過一個例子來證明。
1 public class ObjectParamTransfer2 { 2 Time time1; 3 Time time2; 4
5 public static void main(String[] args) { 6 ObjectParamTransfer2 opt = new ObjectParamTransfer2(); 7 opt.time1 = new Time(); 8 opt.time2 = new Time(); 9 opt.time1.hour = 12; 10 opt.time2.hour = 23; 11 System.out.println("交換前的值:"); 12 System.out.println("time1.hour=" + opt.time1.hour); 13 System.out.println("time2.hour=" + opt.time2.hour); 14
15 opt.swap(opt.time1, opt.time2); 16 System.out.println("交換后的值:"); 17 System.out.println("time1.hour=" + opt.time1.hour); 18 System.out.println("time2.hour=" + opt.time2.hour); 19 } 20
21 private void swap(Time t1, Time t2) { 22 Time temp; 23 temp = t1; 24 t1 = t2; 25 t2 = temp; 26 } 27
28 }
運行結果如下:
交換前的值: time1.hour=12 time2.hour=23 交換后的值: time1.hour=12 time2.hour=23
這里寫了一個交換兩個引用的swap的方法。但是我們從結果中發現調用該方法后輸出結果並沒有發生改變。說明該方法並沒有對opt.time1和opt.time2這兩個引用進行交換。在該方法中只是對參數t1,t2進行交換,驗證了上個例子中引用傳遞的是內存空間地址值,並非參數就是該引用(即傳的不是引用)。對參數的操作並不會影響原來的引用,只會影響參數和引用所指的同一個內存空間里面的內容。這就證明了引用類型參數傳遞並不是傳引用,而只是傳該引用的內存地址值。
3.參數傳遞中的一種特殊情況
在上面的例子中我們已經知道了基本類型的參數傳遞傳的是傳數值,引用類型的參數傳遞傳的是內存地址值。但我在學習過程中碰到一種特殊情況:
1 public class Test { 2 public static void main(String[] args) { 3 String str = new String("abc"); 4 change1(str); 5 System.out.println(str); 6 } 7
8 private static void change1(String str1) { 9 str1 += "123"; 10 System.out.println(str1); 11 } 12 }
運行結果:
abc123
abc
按上面得出的結論來看,引用類型的參數傳遞傳遞的是內存地址值,str和str1指向的是同一個內存空間,str1將內存空間里面的內容改變后輸出str也應該發生改變。但是str指向的內存空間里的內容“abc”並沒有發生變化。這里我理解為String類型的引用傳遞傳的是內容,並不是內存空間地址值。(與第一個例子中傳數值類似)並不會影響原來引用所指的內存空間的內容。可能這也是String對象內容不可變的原因?
因為目前還在基礎階段,學習的還不夠深刻自己也有點疑問,以上理解可能存在偏差和錯誤,如有錯誤請大家指出。