天天看點

你真的搞懂了參數傳遞方式嗎?(多圖超詳細)

文章目錄

  • ​​引入​​
  • ​​參數傳遞的兩種方式​​
  • ​​深入了解按值調用​​
  • ​​引用資料類型的按值調用​​
  • ​​按引用調用​​
  • ​​證明:在java中總是值傳遞​​

引入

在學習程式設計語言的過程中,我相信大多數人都遇到或者經曆過一個問題,有的時候你把變量傳入了一個方法,經過方法内部的一頓操作之後,發現那個變量并沒有發生變化。如果是這樣也就算了,關鍵是有時候你傳入的變量經過方法中的操作後它又發生了變化。這是啥情況?😂莫非每次向方法中傳入參數都是一場豪賭嗎?還是遇事不決量子力學,莫非是那股神奇的力量?😎好吧扯遠了,回歸正題,歸根結底是因為你沒有徹底的弄明白程式設計語言的參數傳遞過程!

參數傳遞的兩種方式

我相信大多數人都知道參數的兩種傳遞方式:

  • ​按值調用​

    ​(call by value)
  • ​按引用調用​

    ​(call by reference)

這個針對大多數的程式設計語言是成立的,當然也有例外,例如:c++還有一個按指針傳遞(不過都可以按如上這兩種了解)。

在很久很久之前還有一個按名調用(call by name)

不過大家放心,現在已經棄用(( •̀ ω •́ )✧ 虛晃一槍)

​按值調用​

​​表示方法接收的是調用者提供的值。

​​

​按引用調用​

​表示方法接收的是調用者提供的變量位址。

講到這裡有人可能會說這些我都知道,确實很多人都知道,但也隻知道這些了,沒有深入的了解,如此的話相當于還是沒懂。

接下來上菜!🤞

深入了解按值調用

在這裡我們以java語言為例

Java程式設計語言總是采用按值調用。也就是說,方法得到的是所有參數值的一個副本。 ------《Java核心技術 卷Ⅰ》

這句話說的相當的透徹,但是俺還是要提幾句。什麼是參數值?參數值就是你那個變量裡面到底裝的是個啥玩楞。怎麼樣夠通俗吧😎。那麼什麼是副本?副本這個說法太高大上了,我們換個說法分身,這個知道吧,就是孫悟空用毫毛變的那個分身,分身終歸是分身,它并不是本體!

我們再合起來了解這句話,也就是說按值調用,就是把變量裡面裝的那個東西傳到方法的形參,自己真身還在外面,自己的分身進到方法裡去了。

現在我們來舉個例子(為了各種語言使用者都能了解,以下使用我的自創語言,跳出三界之外,不在五行之中(●ˇ∀ˇ●)):

方法A(形參){把傳進來的數加個2} //定義方法A
a = 2
方法A(a)  //把a傳進方法A      

a這個變量裡面裝的就是2,他把自己的2複制(分身),傳到了方法中(可以說給了形參),這個方法是對他這個分身做出一系列操作,随着方法的執行結束,他的分身也就被五馬分屍直接拜拜了,跟他的本體沒有啥關系。

來張圖解析一下:

你真的搞懂了參數傳遞方式嗎?(多圖超詳細)

我們都知道對于基本資料類型,變量裡面裝的是一個具體的結果;而對于引用資料類型,變量裡面裝的是位址。有些人錯誤的認為隻要是傳了個引用資料進方法,那就是按引用調用的參數傳遞方式。大錯特錯🤦‍♂️,接下來我們就看一下對于引用資料類型的值傳遞。

引用資料類型的按值調用

還是用我自創的語言,為大家舉個例子:

方法A(形參x){對傳入的對象的屬性進行改動}
a = 某類的對象
方法A(a)      

還記得我們的方法論嗎?

按值調用,就是把變量裡面裝的那個東西傳到方法的形參,自己真身還在外面,自己的分身進到方法裡去了。

同樣的我們也按照上面的方法進行了解。a變量的裡面裝的是對象的位址,然後a把這個位址複制一份給了形參x,這個分身進入方法中完成屬性的改動。

如此一套猛如虎的操作進行下來,一看最後結果傻了眼。不是說進去的是分身,怎麼a的屬性變了?因為當a把自己的位址給了形參x之後,形參x也擁有了一個指向對象的指針,有了這條指針,當然可以進行改動!

看圖!(〃 ̄︶ ̄)人( ̄︶ ̄〃):

你真的搞懂了參數傳遞方式嗎?(多圖超詳細)

縱使形參x在方法執行完畢之後會被回收,但是a指向的對象還在,他造成的影響也還在。

按引用調用

按引用調用,很多人第一反應,就是傳位址,這沒錯,但是關鍵點在于傳什麼的位址。很多人不明白按引用調用的本質,就是因為這個地方沒搞明白。

給你舉個例子:

現在有一個變量a,裡面裝着某個對象的位址

你真的搞懂了參數傳遞方式嗎?(多圖超詳細)

将變量a傳入方法,倘若是按引用調用,傳位址,傳哪個?這就是引用調用的核心!

​按引用調用​

​表示方法接收的是調用者提供的變量位址。

也就是說給形參的是那個0x1122的位址,而這個0x1122就是變量a在記憶體中的位址值,換句話說按引用調用相當于直接把真身放到方法中去,這回是孫悟空親自出山,而不是他的分身了!(~ ̄(OO) ̄)ブ

還沒有完全搞懂?沒事👌,接下來我們通過一個證明來加深了解!

證明:在java中總是值傳遞

此實驗參考《Java程式設計思想》

首先我們編寫一個交換兩個Employee對象的方法:

public static void swap(Employee x,Employee y){
  Employee temp = x;
  x = y;
  y = temp;
}      

如果Java對對象采用的是按引用調用,那麼這個方法就應該實作交換:

var a = new Employee{"Alice",·····};
var b = new Employee{"Bob",······}
swap(a,b);      

但是最終失敗了,兩者沒有發生交換。

我們可以看看兩種情況的記憶體解析圖:

如果是按值調用:

你真的搞懂了參數傳遞方式嗎?(多圖超詳細)

可以看到任x、y如何亂搞,a、b都紋絲不動,是以最後的結果出來,兩者是沒有交換的。

如果是按引用調用:

你真的搞懂了參數傳遞方式嗎?(多圖超詳細)