今天翻看微信上有關Java技術的公眾號時,看到了一篇關於Java中值傳遞的問題,文章討論了在Java中調用函數進行傳參的時候到底是值傳遞還是引用傳遞這個面試時會問到的問題。之前也接觸過類似的問題,但只是知道是值傳遞,具體到為什麼,一直不是太清楚。今天看了一下,算是明白了,寫個博客記錄一下。 首先先聲 ...
今天翻看微信上有關Java技術的公眾號時,看到了一篇關於Java中值傳遞的問題,文章討論了在Java中調用函數進行傳參的時候到底是值傳遞還是引用傳遞這個面試時會問到的問題。之前也接觸過類似的問題,但只是知道是值傳遞,具體到為什麼,一直不是太清楚。今天看了一下,算是明白了,寫個博客記錄一下。
首先先聲明一下,在Java中函數傳參是值傳遞,不是引用傳遞。要弄清楚這個問題之前要先弄清楚什麼是值傳遞,什麼是引用傳遞。
值傳遞(pass by value):是指在調用函數時將實際參數複製一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。
引用傳遞(pass by reference):是指在調用函數時將實際參數的地址直接傳遞到函數中,這樣在函數中如果對參數進行修改,將影響實際參數。
請註意我紅色標記的字,很關鍵。相信很多人對於是值傳遞還是引用傳遞都會有這樣一種認識:在傳遞基本數據類型的時,是值傳遞,在傳遞引用數據類型時是引用傳遞。原因不過就是像下麵這樣的代碼所表現出來的。
package com.wuqi.p1; public class ValuePassTest { public static void main(String[] args) { int a = 1; //傳遞基本數據類型,因為是將a的值傳遞給param,所以即便在pass函數中改變了從 //參數的值,a的值還是不會變。所以我們認為在傳遞基本數據類型的時候是值傳遞 pass(a); System.out.println("a= " + a); } private static void pass(int param) { param = 2; System.out.println("param= " + param); } }
package com.wuqi.p1; import com.wuqi.p2.User; public class PassTest2 { public static void main(String[] args) { User user = new User(); user.setName("wutianqi"); //傳遞對象,因為是將指向User的引用user傳遞給了param, //在函數中param.setName會反應到真實的對象中去。因此我們 //認為在這種情況下是引用傳遞 pass(user); System.out.println("my name is " + user.getName()); } private static void pass(User param) { param.setName("wuqi"); System.out.println("my name is " + param.getName()); } }
包括我自己以前也是這麼認為的。但是我們都沒有註意到這樣一個問題。請看代碼
package com.wuqi.p1; public class PassTest3 { public static void main(String[] args) { String name = "wutianqi"; //這裡傳遞字元串參數,按照我們以前的觀點這裡應該傳遞的是將指向字元串的name引用 //傳遞給param,那麼在pass函數中修改參數的值會直接影響到name引用指向的字元串 //的值,那麼輸出的結果依此應該是 my name is wuqi my name is wuqi pass(name); System.out.println("my name is " + name); } private static void pass(String param) { param = "wuqi"; System.out.println("my name is " + param); } }
這段代碼按照我們對象是引用傳遞的思想,輸出的結果就應該是代碼中所說的那樣。但是真實輸出的結果確實下麵這樣
哎呦!什麼情況!顛覆了你的認知?當初看到這段代碼我也是大吃一驚!這說明之前的認識是錯的!
別慌!讓我們在看一下值傳遞和引用傳遞的概念吧。這裡我標紅的字體起作用了。引用傳遞是直接傳遞引用,那麼在函數中對參數進行修改將會影響到實際參數。按照這個理論,那麼毫無疑問,通過上面的例子,引用傳遞對於Java函數參數傳遞來說是錯誤的。在看看值傳的概念,值傳遞是將實際參數複製一份,對參數的改變不會影響到實際參數。註意複製這兩個字!!!在上面的例子中,如果我們認為是複製了name引用,也就是複製了name引用的值,然後傳遞給param。param="wuqi",其實相當於param=new String("wuqi"),這時param指向了一個新的對象。而實際參數name還是指向原來的對象。這樣的話輸出的結果和正確的就對上了。這樣也就證明瞭在Java中是值傳遞而不是引用傳遞。
對於對象來說傳遞的是引用的一個副本給參數,這一點要銘記!