帶你詳細了解Java值傳遞和引用傳遞
1、什么是值傳遞,什么是引用傳遞?
- 值傳遞(pass by value)是指在調用函數(shù)時將實際參數(shù)復制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對參數(shù)進行修改,將不會影響到實際參數(shù)。
- 引用傳遞(pass by reference)是指在調用函數(shù)時將實際參數(shù)的地址直接傳遞到函數(shù)中,那么在函數(shù)中對參數(shù)所進行的修改,將影響到實際參數(shù)。
2、值傳遞和引用傳遞的區(qū)別是什么?
3、Java中只有值傳遞
3.1 糾正一下大家以前的那些錯誤看法
錯誤理解一:值傳遞和引用傳遞,區(qū)分的條件是傳遞的內(nèi)容,如果是個值,就是值傳遞。如果是個引用,就是引用傳遞
錯誤理解二:Java是引用傳遞。
錯誤理解三:傳遞的參數(shù)如果是普通類型,那就是值傳遞,如果是對象,那就是引用傳遞。
3.2求值策略
我們說當進行方法調用的時候,需要把實際參數(shù)傳遞給形式參數(shù),那么傳遞的過程中到底傳遞的是什么東西呢?
這其實是程序設計中求值策略(Evaluation strategies)的概念。
在計算機科學中,求值策略是確定編程語言中表達式的求值的一組(通常確定性的)規(guī)則。求值策略定義何時和以何種順序求值給函數(shù)的實際參數(shù)、什么時候把它們代換入函數(shù)、和代換以何種形式發(fā)生。
求值策略分為兩大基本類,基于如何處理給函數(shù)的實際參數(shù),分為嚴格的和非嚴格的。
3.3 嚴格求值
在“嚴格求值”中,函數(shù)調用過程中,給函數(shù)的實際參數(shù)總是在應用這個函數(shù)之前求值。多數(shù)現(xiàn)存編程語言對函數(shù)都使用嚴格求值。所以,我們本文只關注嚴格求值。
在嚴格求值中有幾個關鍵的求值策略是我們比較關心的,那就是傳值調用(Call by value)、傳引用調用(Call by reference)以及傳共享對象調用(Call by sharing)
1.傳值調用(值傳遞):在傳值調用中,實際參數(shù)先被求值,然后其值通過復制,在傳遞給被調函數(shù)的形式參數(shù)。因為形式參數(shù)拿到的只是一個"局部拷貝",所以如果在被調函數(shù)中改變了形式參數(shù)的值,并不會改變實際參數(shù)的值。
2.傳引用調用(引用傳遞)在傳引用調用中,傳遞給函數(shù)的是它的實際參數(shù)的隱式引用而不是實參的拷貝。因為傳遞的是引用,所以,如果在被調函數(shù)中改變了形式參數(shù)的值,改變對于調用者來說是可見的。
3.傳共享對象調用(共享對象傳遞)傳共享對象調用中,先獲取到實際參數(shù)的地址,然后將其復制,并把該地址的拷貝傳遞給被調函數(shù)的形式參數(shù)。因為參數(shù)的地址都指向同一個對象,所以我們也稱之為"傳共享對象",所以,如果在被調函數(shù)中改變了形式參數(shù)的值,調用者是可以看到這種變化的。
不知道大家有沒有發(fā)現(xiàn),其實傳共享對象調用和傳值調用的過程幾乎是一樣的,都是進行"求值"、"拷貝"、"傳遞"。你品,你細品。
但是,傳共享對象調用和內(nèi)傳引用調用的結果又是一樣的,都是在被調函數(shù)中如果改變參數(shù)的內(nèi)容,那么這種改變也會對調用者有影響。你再品,你再細品。
那么,共享對象傳遞和值傳遞以及引用傳遞之間到底有很么關系呢?
對于這個問題,我們應該關注過程,而不是結果,因為傳共享對象調用的過程和傳值調用的過程是一樣的,而且都有一步關鍵的操作,那就是"復制",所以,通常我們認為傳共享對象調用是傳值調用的特例
我們先把傳共享對象調用放在一邊,我們再來回顧下傳值調用和傳引用調用的主要區(qū)別:
傳值調用是指在調用函數(shù)時將實際參數(shù)復制一份傳遞到函數(shù)中,傳引用調用是指在調用函數(shù)時將實際參數(shù)的引用直接傳遞到函數(shù)中。

3.3 java 的求值策略
前面我們介紹過了傳值調用、傳引用調用以及傳值調用的特例傳共享對象調用,那么,Java中是采用的哪種求值策略呢?
很多人說Java中的基本數(shù)據(jù)類型是值傳遞的,這個基本沒有什么可以討論的,普遍都是這樣認為的。
但是,有很多人卻誤認為Java中的對象傳遞是引用傳遞。之所以會有這個誤區(qū),主要是因為Java中的變量和對象之間是有引用關系的。Java語言中是通過對象的引用來操縱對象的。所以,很多人會認為對象的傳遞是引用的傳遞。
而且很多人還可以舉出以下的代碼示例:
public static void main(String[] args) {
Test pt = new Test();
User hollis = new User();
hollis.setName("Hollis");
hollis.setGender("Male");
pt.pass(hollis);
System.out.println("print in main , user is " + hollis);
}
public void pass(User user) {
user.setName("hollischuang");
System.out.println("print in pass , user is " + user);
}
輸出結果:
print in pass , user is User{name='hollis', gender='Male'}
print in main , user is User{name='hollischuang', gender='Male'}:
可以看到,對象類型在被傳遞到pass方法后,在方法內(nèi)改變了其內(nèi)容,最終調用方main方法中的對象也變了。
所以,很多人說,這和引用傳遞的現(xiàn)象是一樣的,就是在方法內(nèi)改變參數(shù)的值,會影響到調用方。
但是,其實這是走進了一個誤區(qū)。
其實Java中使用的求值策略就是傳共享對象調用,也就是說,Java會將對象的地址的拷貝傳遞給被調函數(shù)的形式參數(shù)。只不過"傳共享對象調用"這個詞并不常用,所以Java社區(qū)的人通常說"Java是傳值調用",這么說也沒錯,因為傳共享對象調用其實是傳值調用的一個特例。
值傳遞和共享對象傳遞的現(xiàn)象沖突嗎?
看到這里很多人可能會有一個疑問,既然共享對象傳遞是值傳遞的一個特例,那么為什么他們的現(xiàn)象是完全不同的呢?
難道值傳遞過程中,如果在被調方法中改變了值,也有可能會對調用者有影響嗎?那到底什么時候會影響什么時候不會影響呢?
其實是不沖突的,之所以會有這種疑惑,是因為大家對于到底是什么是"改變值"有誤解。
我們先回到上面的例子中來,看一下調用過程中實際上發(fā)生了什么?

在參數(shù)傳遞的過程中,實際參數(shù)的地址0X1213456被拷貝給了形參。這個過程其實就是值傳遞,只不過傳遞的值得內(nèi)容是對象的應用。
那為什么我們改了user中的屬性的值,卻對原來的user產(chǎn)生了影響呢?
其實,這個過程就好像是:你復制了一把你家里的鑰匙給到你的朋友,他拿到鑰匙以后,并沒有在這把鑰匙上做任何改動,而是通過鑰匙打開了你家里的房門,進到屋里,把你家的電視給砸了。
這個過程,對你手里的鑰匙來說,是沒有影響的,但是你的鑰匙對應的房子里面的內(nèi)容卻是被人改動了。
也就是說,Java對象的傳遞,是通過復制的方式把引用關系傳遞了,如果我們沒有改引用關系,而是找到引用的地址,把里面的內(nèi)容改了,是會對調用方有影響的,因為大家指向的是同一個共享對象。
那么我們改變一下pass方法:
public void pass(User user) {
user = new User();
user.setName("hollischuang");
System.out.println("print in pass , user is " + user);
}
再看一下整個過程中發(fā)生了什么:

這個過程,就好像你復制了一把鑰匙給到你的朋友,你的朋友拿到你給他的鑰匙之后,找個鎖匠把他修改了一下,他手里的那把鑰匙變成了開他家鎖的鑰匙。這時候,他打開自己家,就算是把房子點了,對你手里的鑰匙,和你家的房子來說都是沒有任何影響的。
所以,Java中的對象傳遞,如果是修改引用,是不會對原來的對象有任何影響的,但是如果直接修改共享對象的屬性的值,是會對原來的對象有影響的。
4、總結
我們知道,編程語言中需要進行方法間的參數(shù)傳遞,這個傳遞的策略叫做求值策略。
在程序設計中,求值策略有很多種,比較常見的就是值傳遞和引用傳遞。還有一種值傳遞的特例——共享對象傳遞。
值傳遞和引用傳遞最大的區(qū)別是傳遞的過程中有沒有復制出一個副本來,如果是傳遞副本,那就是值傳遞,否則就是引用傳遞。
在Java中,其實是通過值傳遞實現(xiàn)的參數(shù)傳遞,只不過對于Java對象的傳遞,傳遞的內(nèi)容是對象的引用。
我們可以總結說,Java中的求值策略是共享對象傳遞,這是完全正確的。
但是,為了讓大家都能理解你說的,我們說Java中只有值傳遞,只不過傳遞的內(nèi)容是對象的引用。這也是沒毛病的。
但是,絕對不能認為Java中有引用傳遞。
到此這篇關于帶你詳細了解Java值傳遞和引用傳遞的文章就介紹到這了,更多相關Java值傳遞和引用傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java編程通過匹配合并數(shù)據(jù)實例解析(數(shù)據(jù)預處理)
這篇文章主要介紹了Java編程通過匹配合并數(shù)據(jù)實例解析(數(shù)據(jù)預處理),分享了相關代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-01-01
用SpringBoot框架來接收multipart/form-data文件方式
這篇文章主要介紹了用SpringBoot框架來接收multipart/form-data文件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02

