閱讀128 返回首頁    go 阿裏雲 go 技術社區[雲棲]


理解JAVA的傳值方式

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

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


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

  1. 基本類型
  2. 接口類型
  3. 類類型
  4. 數組類型

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

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

數字類型又分為

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

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

先看參數為基本類型的情況:

01 public class Demo1 {
02     public void swap(int a, int b) {
03         a = a ^ b;
04         b = a ^ b;
05         a = a ^ b;
06         System.out.println("swap: a=" + a + ",b=" + b);
07     }
08  
09     public static void main(String[] args) {
10         Demo1 demo1 = new Demo1();
11         int a = 1;
12         int b = 2;
13         demo1.swap(a, b);
14         System.out.println("main: a=" + a + ",b=" + b);
15     }
16 }

輸出

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

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

再看參數為引用的情況:

01 </pre>
02 <pre>public class Demo2 {
03      public void swap(StringBuffer a,StringBuffer b){
04             StringBuffer c = a;
05             a=b;
06             b=c;
07          System.out.println("swap: a="+a+",b="+b);
08      }
09  
10    public static void main(String[] args) {
11       StringBuffer a = new StringBuffer("a");
12       StringBuffer b = new StringBuffer("b");
13       Demo2 demo2 = new Demo2();
14       demo2.swap(a, b);
15       System.out.println("main: a="+a+",b="+b);
16    }
17 }</pre>
18 <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指向的對象的值.再看下麵的例子:

01 </pre>
02 public class Demo3 {
03  public void swap(StringBuffer a,StringBuffer b){
04  a.append(b);
05  StringBuffer c = a;
06  a=b;
07  b=c;
08  System.out.println("swap: a="+a+",b="+b);
09  }
10  public static void main(String[] args) {
11  StringBuffer a = new StringBuffer("a");
12  StringBuffer b = new StringBuffer("b");
13  Demo3 demo3 = new Demo3();
14  demo3.swap(a, b);
15  System.out.println("swap: a="+a+",b="+b);
16  }
17 }
18 這個會輸出什麼呢?
19  
20 swap: a=b,b=ab
21 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傳遞的隻會是值,沒有傳遞引用.

最後更新:2017-05-22 14:32:48

  上一篇:go  如何在 AWS EC2 的 Linux 服務器上開放一個端口
  下一篇:go  從volatile解讀ConcurrentHashMap(jdk1.6.0)無鎖讀