1. 程式人生 > >Java語言中的值傳遞與引用傳遞

Java語言中的值傳遞與引用傳遞

JAVA語言中的傳遞都是值傳遞嗎?有沒有引用傳遞呢?這是一個常常被討論的問題。開始以前首先來看下面的程式碼:

public class TestParameter {
 // 初始值為0
 protected int num = 0;

 // 為方法引數重新賦值
 public void change(int i) {
  i = 5;
 }

 // 為方法引數重新賦值
 public void change(TestParameter t) {
  TestParameter tmp = new TestParameter();
  tmp.num = 9;
  t = tmp;
 }

 // 改變方法引數的值
 public void add(int i) {
  i += 10;
 }

 // 改變方法引數屬性的值
 public void add(TestParameter pt) {
  pt.num += 20;
 }

 public static void main(String[] args) {
  TestParameter t = new TestParameter();
  System.out.println("引數--基本型別");
  System.out.println("原有的值:" + t.num);
  // 為基本型別引數重新賦值
  t.change(t.num);
  System.out.println("賦值之後:" + t.num);
  // 為引用型引數重新賦值
  t.change(t);
  System.out.println("運算之後:" + t.num);

  System.out.println();

  t = new TestParameter();
  System.out.println("引數--引用型別");
  System.out.println("原有的值:" + t.num);
  // 改變基本型別引數的值
  t.add(t.num);
  System.out.println("賦引用後:" + t.num);
  // 改變引用型別引數所指向物件的屬性值
  t.add(t);
  System.out.println("改屬性後:" + t.num);
 }
}

這段程式碼執行結果如下:

引數--基本型別
原有的值:0
賦值之後:0
運算之後:0

引數--引用型別
原有的值:0
賦引用後:0
改屬性後:20

從上面這個程式碼的執行結果可以看出:
首先,對於基本型別,在方法體內對方法引數進行重新賦值,並不會改變原有變數的值。
其次,對於引用型別,在方法體內對方法引數進行重新賦予引用,並不會改變原有變數所持有的引用。
另外,方法體內對引數進行運算,不影響原有變數的值。方法體內對引數所指向物件的屬性進行運算,將改變原有變數所指向物件的屬性值。

為什麼會出現這樣的現象呢?這就要說到值傳遞和引用傳遞的概念了。這個問題向來是頗有爭議的,就連Think in Java 的作者Eckel都參與爭論。

大家知道,JAVA中變數有以下兩種:
1.基本型別變數,包括char、byte、short、int、long、float、double、boolean。
2.引用型別變數,包括類、介面、陣列(基本型別陣列和物件陣列)。

當基本型別的變數被當作引數傳遞給方法時,JAVA虛擬機器所做的工作是把這個值拷貝了一份,然後把拷貝後的值傳遞到了方法的內部。因此在上面的例子中,我們回頭來看看這個方法:
// 為方法引數重新賦值
public void change(int i) {
 i = 5;
}
在這個方法被呼叫時,變數i和TestParameter型物件t的屬性num具有相同的值,卻是兩個不同變數。變數i是由JAVA虛擬機器建立的作用域在 change(int i)方法內的區域性變數,在這個方法執行完畢後,它的生命週期就結束了。在基本型別被作為引數傳遞給一方時,是值傳遞,在整個過程中沒有牽扯到引用這個概念。這也是大家所公認的。

在基本型別被作為引數傳遞給方式時,是值傳遞,在整個過程中根本沒有牽扯到引用這個概念。對於布林型變數當然也是如此,我們看看下面的例子:

public class TestBooleanParameter {
 // 布林型值
 boolean bool = true;

 // 為布林型引數重新賦值
 public void change(boolean b) {
  b = false;
 }

 // 對布林型引數進行運算
 public void calculate(boolean b) {
  b = b && false;
  // 為了方便對比,將運算結果輸出
  System.out.println("b運算後的值:" + b);
 }

 public static void main(String[] args) {
  TestBooleanParameter t = new TestBooleanParameter();

  System.out.println("引數--布林型");
  System.out.println("原有的值:" + t.bool);
  // 為布林型引數重新賦值
  t.change(t.bool);
  System.out.println("賦值之後:" + t.bool);

  // 改變布林型引數的值
  t.calculate(t.bool);
  System.out.println("運算之後:" + t.bool);
 }
}

輸出結果如下:
引數--布林型
原有的值:true
賦值之後:true
運算後的值:false
運算之後:true