實際上對這兩種傳遞方式,知乎上有個回答說得很好:app
值傳遞和引用傳遞,屬於函數調用時參數的求值策略(Evaluation Strategy),這是對調用函數時,求值和傳值的方式的描述,而非傳遞的內容的類型(內容指:是值類型仍是引用類型,是值仍是指針)。iphone
值類型/引用類型,是用於區分兩種內存分配方式,值類型在調用棧上分配,引用類型在堆上分配。函數
一個描述內存分配方式,一個描述參數求值策略,二者之間無任何依賴或約束關係。ui
實際上意思就是,在函數調用時,不要經過傳進去的參數類型去判斷是值傳遞仍是引用傳遞,而是要看這種語言具體的求值策略。lua
在函數調用過程當中,調用方提供實參,這些實參能夠是常量:spa
Call(1); // 常量 Call(x); // 變量 Call(2 * x + 1); // 常量與變量的組合 Call(GetNumber()); // 對其它函數的調用
可是全部這些實參的形式,都統稱爲表達式(Expression)。指針
求值(Evaluation)便是指對這些表達式的簡化並求解其值的過程。code
求值策略(值傳遞和引用傳遞)的關注的點在於,這些表達式在調用函數的過程當中,求值的時機、值的形式的選取等問題。求值的時機,能夠是在函數調用前,也能夠是在函數調用後,由被調用者本身求值。這裏所謂調用後求值,能夠理解爲Lazy Load或On Demand的一種求值方式。對象
除了值傳遞和引用傳遞,還有一些其它的求值策略,詳見下表:blog
求值策略 |
求值時間 |
傳值方式 |
值傳遞(Pass by value) |
調用前 |
值的結果(是原值的副本) |
引用傳遞(Pass by reference) |
調用前 |
原值(原始對象,無副本) |
名傳遞(Pass by name) |
調用後(用到才求值) |
與值無關的一個名 |
重點是值傳遞和引用傳遞。上面給出的傳值方式的表述有些單薄,下表列出了一些兩者在行爲表象上的區別:
值傳遞 |
引用傳遞 |
|
根本區別 |
會建立副本(Copy) |
不建立副本 |
結果 |
函數中沒法改變原始對象 |
函數中能夠改變原始對象 |
這裏的改變不是指mutate, 而是change,指把一個變量指向另外一個對象,而不是指僅僅改變屬性或是成員什麼的,因此說Java是Pass by value,緣由是它調用時Copy,實參不能指向另外一個對象,而不是由於被傳遞的東西本質上是個Value。
這些行爲,與參數類型是值類型仍是引用類型無關。對於值傳遞,不管是值類型仍是引用類型,都會在調用棧上建立一個副本,不一樣是,對於值類型而言,這個副本就是整個原始值的複製。而對於引用類型而言,因爲引用類型的實例在堆中,在棧上只有它的一個引用(通常狀況下是指針),其副本也只是這個引用的複製,而不是整個原始對象的複製。
綜上所述,對於Java的函數調用方式最準確的描述是:參數藉由值傳遞方式,傳遞的值是個引用。(句中兩個「值」不是一個意思,第一個值是evaluation result,第二個值是value content)。
int num = 10; String str = "hello";
num是基本類型,值就直接保存在變量中。而str是引用類型,變量中保存的只是實際對象的地址。通常稱這種變量爲"引用",引用指向實際對象,實際對象中保存着內容,比較特別的是,string對象是不可變對象
1) 基本類型
void foo(int value) { value = 100; } foo(num); // num 沒有被改變
傳進foo()裏的只是num的一個副本。
2) 沒有提供改變自身方法的引用類型
void foo(String text) { text = "world"; } str=」hello」 foo(str); // str 也沒有被改變
整個過程以下圖所示:
3) 提供了改變自身方法的引用類型
StringBuilder sb = new StringBuilder("iphone"); void foo(StringBuilder builder) { builder.append("4"); } foo(sb); // sb指向內容被改變了,變成了"iphone4",但自己仍是指向一樣的地址。
append前:
append後:
4)
提供了改變自身方法的引用類型,可是不使用,而是使用賦值運算符
StringBuilder sb = new StringBuilder("iphone"); void foo(StringBuilder builder) { builder = new StringBuilder("ipad"); } foo(sb); // sb指向內容沒有被改變,仍是 "iphone"。
賦值前:
賦值後:
(完)