天天看點

Stackoverflow問答:Java是傳值還是傳引用?

原文位址 譯者:葉文海([email protected]

譯者注:這是一篇在stackoverflow上面的一個經典問題,也是java開發者容易混淆的一個問題,我節選了其中兩個vote最高的回複進行翻譯。

問題:我一直認為java的參數是按引用傳遞,然而我看過一些文章裡說java的參數并不是按引用傳遞的,比如這篇,這讓我很迷惑。java中的參數到底是按引用傳遞還是按值傳遞?

在java裡參數是按值來傳遞的。比較難了解的可能是java傳遞的是對象的引用,但這些引用是按值傳遞。

比如:

在這個例子裡面,執行完foo()方法之後,在main方法裡再調用adog.getname()方法依然會傳回”max”,在main方法中的

adog并沒有因為foo()的執行而被重寫,這說明了參數是按值來進行傳遞的。如果是按照引用來傳遞的話在執行完foo()

方法之後adog.getname()将會傳回”fifi”。

就像這樣:

我剛剛發現你引用了我的文章

Stackoverflow問答:Java是傳值還是傳引用?

(譯者注:這位是提問者引用文章的作者)

在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的指向就會被改變。

可以把引用參數當成被傳遞參數的别名,當這個别名被指派的時候就相當于被傳遞的參數被指派。

這對你有幫助嗎?(我會把這個回答補充到我的文章裡面去)。