原文位址 譯者:葉文海([email protected])
譯者注:這是一篇在stackoverflow上面的一個經典問題,也是java開發者容易混淆的一個問題,我節選了其中兩個vote最高的回複進行翻譯。
問題:我一直認為java的參數是按引用傳遞,然而我看過一些文章裡說java的參數并不是按引用傳遞的,比如這篇,這讓我很迷惑。java中的參數到底是按引用傳遞還是按值傳遞?
在java裡參數是按值來傳遞的。比較難了解的可能是java傳遞的是對象的引用,但這些引用是按值傳遞。
比如:
在這個例子裡面,執行完foo()方法之後,在main方法裡再調用adog.getname()方法依然會傳回”max”,在main方法中的
adog并沒有因為foo()的執行而被重寫,這說明了參數是按值來進行傳遞的。如果是按照引用來傳遞的話在執行完foo()
方法之後adog.getname()将會傳回”fifi”。
就像這樣:
我剛剛發現你引用了我的文章

(譯者注:這位是提問者引用文章的作者)
在java的規範裡說明了在java中一切參數都是按值傳遞的,根本就沒有引用傳遞這一說。
了解這個概念的關鍵是要明白
這裡聲明的并不是一個dog對象,而是一個指向dog對象的指針。
這是什麼意思呢,就是當你執行
本質上是你把建立好的dog對象的位址傳遞給foo方法。(我說的‘本質上’其實是因為java中的指針并不是直接的位址,不過可以簡單的了解成這樣)。
假設dog對象在記憶體中的位址是42。那我們就是把42這個值傳遞給了foo方法。
如果foo方法的定義如下:
讓我們來看看執行的時候會發生些什麼。
1. somedog的值設定為42。
2. 在aaa行
a.somedog指向一個記憶體位址為42的dog對象。
b.把dog(記憶體位址為42)對象的name屬性改為max。
3. 在bbb行
a.一個新的dog對象被建立,我們假設它的記憶體位址是74。
b.把這個74的記憶體位址值賦給somedog。
4. 在ccc行
a.somedog指向一個記憶體位址為74的dog對象。
b.把dog(記憶體位址為74)對象的name屬性改為rowlf。
5. 方法執行完畢。
現在讓我們來想想在這個方法外面發生了什麼:
mydog改變了嗎?
這個問題的關鍵在于:
要明确mydog是一個指針,而不是一個實際的dog對象。是以答案是它沒有改變,mydog的值還是42;它指向的還是最開始的那個dog對象(雖然在foo方法中的aaa行把它指向對象的name屬性改成了max,但是它指向的還是那個最初的dog對象)。
這驗證了改變所指對象的屬性,但沒有改變其指向。
java的運作機制跟c很像。你可以給一個指針指派,然後把這個指針傳遞給一個方法,之後在這個方法中你可以改變這個指針指向對象的資料,但是你不能改變這個指針的指向。
在c++,ada,pascal以及其他支援引用傳遞的語言中你可以直接改變傳遞的參數。如果java是引用傳遞的話,那麼在執行上面定義的foo方法的bbb行的時候somedog的指向就會被改變。
可以把引用參數當成被傳遞參數的别名,當這個别名被指派的時候就相當于被傳遞的參數被指派。
這對你有幫助嗎?(我會把這個回答補充到我的文章裡面去)。