1. 程式人生 > >理解JAVA的傳值方式

理解JAVA的傳值方式

作者:黑伯

問題: Java的引數傳遞的是值還是引用?

我們經常會被問到這樣的問題,當我呼叫某個方法時,通過引數傳遞過去的是變數本身,還是一個變數的複製品?問題的答案留到討論後給出。


首先,你需要了解下java變數的分類:java中的變數分為

  1. 基本型別
  2. 介面型別
  3. 類型別
  4. 陣列型別

其中後面三種統稱為引用型別,而基本型別分為三種,

  1. 數字型別
  2. boolean
  3. returnAddress

數字型別又分為

  1. 浮點型別
  2. 整數型別
  3. 浮點

整數又有具體的內容,這裡不再展開說明。其中,returnAddress是java虛擬機器內部使用的型別,它被用來實現java程式中finally子句。這裡主要看引用型別和基本型別數字型別情況(boolean型別的情況和基本型別一致).

先看引數為基本型別的情況:

public class Demo1 {
    public void swap(int a, int b) {
        a = a ^ b;
        b = a ^ b;
        a = a ^ b;
        System.out.println("swap: a=" + a + ",b=" + b);
    }

    public static void main(String[] args) {
        Demo1 demo1 = new Demo1();
        int a = 1;
        int b = 2;
        demo1.swap(a, b);
        System.out.println("main: a=" + a + ",b=" + b);
    }
}

輸出

swap: a=2,b=1
main: a=1,b=2

上面的程式碼想通過swap互動a和b的值,在swap內部,變數a和b已經交換成功了,但在main中a和b的值依然是原來的值.

再看引數為引用的情況:

</pre>
<pre>public class Demo2 {
     public void swap(StringBuffer a,StringBuffer b){
            StringBuffer c = a;
            a=b;
            b=c;
         System.out.println("swap: a="+a+",b="+b);
     }

   public static void main(String[] args) {
      StringBuffer a = new StringBuffer("a");
      StringBuffer b = new StringBuffer("b");
      Demo2 demo2 = new Demo2();
      demo2.swap(a, b);
      System.out.println("main: a="+a+",b="+b);
   }
}</pre>
<pre>

大家可以先思考下,上面的輸出是什麼?

輸出:
swap: a=b,b=a
main: a=a,b=b

和引數為基本型別的情況結果是一致的.
為什麼會出現這種情況呢?

我們來分析下上面的引數傳遞過程,以Demo2為例:

圖1是swap未計算前的引數值,

圖2是swap計算後的引數值.

從圖中可以看出,swap的計算過程只能改變swap內部變數a和b的值,不能改變main中的a和b變數的引用值,換言之,引數的傳遞只能傳值,不存在傳引用一說.

請注意,上面我說不能改變a和b變數的引用值,可沒說不能改變a和b指向的物件的值.再看下面的例子:

</pre>
public class Demo3 {
 public void swap(StringBuffer a,StringBuffer b){
 a.append(b);
 StringBuffer c = a;
 a=b;
 b=c;
 System.out.println("swap: a="+a+",b="+b);
 }
 public static void main(String[] args) {
 StringBuffer a = new StringBuffer("a");
 StringBuffer b = new StringBuffer("b");
 Demo3 demo3 = new Demo3();
 demo3.swap(a, b);
 System.out.println("swap: a="+a+",b="+b);
 }
}
這個會輸出什麼呢?

swap: a=b,b=ab
swap: a=ab,b=b

這個就是上面所說的,在swap內部的計算過程中,改變了main.a所指向物件的值.

就像下面的圖所描述的那樣:

但根本上,swap不能改變main中a和b的引用值.

另外貼一句sun公司官方文件上的描述這一問題的原話:

Java is always pass-by-value.when object is passed as a argument, be careful with that it is also the copy of reference

所以,現在你應該知道,java傳遞的只會是值,沒有傳遞引用.