Praxis 1. Understand that parameters are passed by value not by reference

什麼是 Pass By Value ?什麼是 Pass by Reference ?

Pass By Reference 的概念就像是我給你一個網址 , 你連進去看網頁的內容,如果你把內容改了,我看到得東西也會一起改變,反過來說,如果我把內容改了,你也會看到我修改後的內容。

Pass By Value 是我把網頁的內容印給你,你可以看到內容,也可以在上面畫線、加字,但修改的的內容,不會受到影響我在看的網頁。

Pass By Value 的概念像是把內容複製一份再傳給別人,這個複製的概念很重要,等等會用上。

Java 是 Pass By Value 的嗎 ?

第一個範例

先猜一下,下面程式碼的執行結果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
private static void runCase1() {
int j = 10;
Point point = new Point(4, 4);

logger.info("修改前的 Point {}, 修改前的 j ={}", point, j);
setPointLocation(point, j); // 呼叫下面的 function
logger.info("修改後的 Point {}, 修改後的 j ={}", point, j);

}

private static void setPointLocation(Point pointInst, int otherJ) {
// 把 Point 的位置改成 5, 5
pointInst.setLocation(5, 5);

// 把 j 的值改為 20
otherJ = 20;
logger.info("在修改的過程中 Point = {}, j ={}", pointInst, otherJ);
}

答案可能會有三個選項:

  • (A) 修改後的 Point 為 5,5 , j 為 20
  • (B) 修改後的 Point 為 5,5 , j 為 10
  • (C) 修改後的 Point 為 4,4 , j 為 10

正確答案為 B.

Point 和 int 的運作方式,好像不太一樣, 兩個參數丟到 setPointLocation 值都有被修改,為什麼 int 沒有被修改,但 point 的值卻改變了。

Reference type 的運作方式

像 Point 這種 Object,把他歸類為 reference type

Point point = new Point(4, 4); 宣告一個變數 point 指向 Point 實體

setPointLocation(point, j); 準備開始把參數複製後傳給方法

接著,既然 pointInst 是複製來的,指向的實體也會是同一個實體

所以當 pointInst 呼叫 setLocation 的時候等同 point 呼叫 setLocation

Primitive type 的運作方法

同樣的看一下 int 變數 j 的狀況,一樣有個複製的動作。

竟然是複製過來的,所以 otherJ 在改變值的過程中,就不會影響原來的 j

第二個範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private static void runCase2() {
int j = 10;
Point point = new Point(4, 4);
logger.info("修改前的 Point {}, 修改前的 j ={}", point, j);
setPointWithAssign(point, j);
logger.info("修改後的 Point {}, 修改後的 j ={}", point, j);

}

private static void setPointWithAssign(Point pointInst, int j) {
pointInst = new Point(6, 6);
j = 20;
logger.info("在修改的過程中 Point = {}, j ={}", pointInst, otherJ);
}

答案可能會有三個選項:

  • (A) 修改後的 Point 為 6,6 , j 為 20
  • (B) 修改後的 Point 為 6,6 , j 為 10
  • (C) 修改後的 Point 為 4,4 , j 為 10

正確答案為 C.

Reference type 的運作方式

同樣的 Point Point point = new Point(4, 4); 宣告一個變數 point 指向 Point 實體

setPointWithAssign(point, j); 準備開始把參數複製後傳給方法

同樣的,既然 pointInst 是複製來的,指向的實體也會是同一個實體

但這時候,pointInst = new Point(6, 6);,pointInst 直接產生一個新的 Point 實體

所以竟然已經指向新的 Point 實體,所有的改動和原來的 point 就完全不影響了。

Primitive type 的運作方法

和範例一的運作一模一樣,不解釋。

Java 是 Pass By Value 的

只要在參數傳遞的過程,有類似複製一份的概念,可以視為是 Pass By Value ,在 Java 的參數傳遞過程中,無論是 reference type 或著 primitive type,都會複製一份,傳到方法中。

而容易混淆的部分是 reference type 複製的是一個 reference ,primitive type 複製的是一個 value。