帶你詳細了解Java值傳遞和引用傳遞
1、什么是值傳遞,什么是引用傳遞?
- 值傳遞(pass by value)是指在調(diào)用函數(shù)時將實際參數(shù)復(fù)制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對參數(shù)進行修改,將不會影響到實際參數(shù)。
- 引用傳遞(pass by reference)是指在調(diào)用函數(shù)時將實際參數(shù)的地址直接傳遞到函數(shù)中,那么在函數(shù)中對參數(shù)所進行的修改,將影響到實際參數(shù)。
2、值傳遞和引用傳遞的區(qū)別是什么?
3、Java中只有值傳遞
3.1 糾正一下大家以前的那些錯誤看法
錯誤理解一:值傳遞和引用傳遞,區(qū)分的條件是傳遞的內(nèi)容,如果是個值,就是值傳遞。如果是個引用,就是引用傳遞
錯誤理解二:Java是引用傳遞。
錯誤理解三:傳遞的參數(shù)如果是普通類型,那就是值傳遞,如果是對象,那就是引用傳遞。
3.2求值策略
我們說當進行方法調(diào)用的時候,需要把實際參數(shù)傳遞給形式參數(shù),那么傳遞的過程中到底傳遞的是什么東西呢?
這其實是程序設(shè)計中求值策略(Evaluation strategies)的概念。
在計算機科學中,求值策略是確定編程語言中表達式的求值的一組(通常確定性的)規(guī)則。求值策略定義何時和以何種順序求值給函數(shù)的實際參數(shù)、什么時候把它們代換入函數(shù)、和代換以何種形式發(fā)生。
求值策略分為兩大基本類,基于如何處理給函數(shù)的實際參數(shù),分為嚴格的和非嚴格的。
3.3 嚴格求值
在“嚴格求值”中,函數(shù)調(diào)用過程中,給函數(shù)的實際參數(shù)總是在應(yīng)用這個函數(shù)之前求值。多數(shù)現(xiàn)存編程語言對函數(shù)都使用嚴格求值。所以,我們本文只關(guān)注嚴格求值。
在嚴格求值中有幾個關(guān)鍵的求值策略是我們比較關(guān)心的,那就是傳值調(diào)用(Call by value)、傳引用調(diào)用(Call by reference)以及傳共享對象調(diào)用(Call by sharing)
1.傳值調(diào)用(值傳遞):在傳值調(diào)用中,實際參數(shù)先被求值,然后其值通過復(fù)制,在傳遞給被調(diào)函數(shù)的形式參數(shù)。因為形式參數(shù)拿到的只是一個"局部拷貝",所以如果在被調(diào)函數(shù)中改變了形式參數(shù)的值,并不會改變實際參數(shù)的值。
2.傳引用調(diào)用(引用傳遞)在傳引用調(diào)用中,傳遞給函數(shù)的是它的實際參數(shù)的隱式引用而不是實參的拷貝。因為傳遞的是引用,所以,如果在被調(diào)函數(shù)中改變了形式參數(shù)的值,改變對于調(diào)用者來說是可見的。
3.傳共享對象調(diào)用(共享對象傳遞)傳共享對象調(diào)用中,先獲取到實際參數(shù)的地址,然后將其復(fù)制,并把該地址的拷貝傳遞給被調(diào)函數(shù)的形式參數(shù)。因為參數(shù)的地址都指向同一個對象,所以我們也稱之為"傳共享對象",所以,如果在被調(diào)函數(shù)中改變了形式參數(shù)的值,調(diào)用者是可以看到這種變化的。
不知道大家有沒有發(fā)現(xiàn),其實傳共享對象調(diào)用和傳值調(diào)用的過程幾乎是一樣的,都是進行"求值"、"拷貝"、"傳遞"。你品,你細品。
但是,傳共享對象調(diào)用和內(nèi)傳引用調(diào)用的結(jié)果又是一樣的,都是在被調(diào)函數(shù)中如果改變參數(shù)的內(nèi)容,那么這種改變也會對調(diào)用者有影響。你再品,你再細品。
那么,共享對象傳遞和值傳遞以及引用傳遞之間到底有很么關(guān)系呢?
對于這個問題,我們應(yīng)該關(guān)注過程,而不是結(jié)果,因為傳共享對象調(diào)用的過程和傳值調(diào)用的過程是一樣的,而且都有一步關(guān)鍵的操作,那就是"復(fù)制",所以,通常我們認為傳共享對象調(diào)用是傳值調(diào)用的特例
我們先把傳共享對象調(diào)用放在一邊,我們再來回顧下傳值調(diào)用和傳引用調(diào)用的主要區(qū)別:
傳值調(diào)用是指在調(diào)用函數(shù)時將實際參數(shù)復(fù)制
一份傳遞到函數(shù)中,傳引用調(diào)用是指在調(diào)用函數(shù)時將實際參數(shù)的引用直接
傳遞到函數(shù)中。
3.3 java 的求值策略
前面我們介紹過了傳值調(diào)用、傳引用調(diào)用以及傳值調(diào)用的特例傳共享對象調(diào)用,那么,Java中是采用的哪種求值策略呢?
很多人說Java中的基本數(shù)據(jù)類型是值傳遞的,這個基本沒有什么可以討論的,普遍都是這樣認為的。
但是,有很多人卻誤認為Java中的對象傳遞是引用傳遞。之所以會有這個誤區(qū),主要是因為Java中的變量和對象之間是有引用關(guān)系的。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); }
輸出結(jié)果:
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)容,最終調(diào)用方main方法中的對象也變了。
所以,很多人說,這和引用傳遞的現(xiàn)象是一樣的,就是在方法內(nèi)改變參數(shù)的值,會影響到調(diào)用方。
但是,其實這是走進了一個誤區(qū)。
其實Java中使用的求值策略就是傳共享對象調(diào)用,也就是說,Java會將對象的地址的拷貝傳遞給被調(diào)函數(shù)的形式參數(shù)。只不過"傳共享對象調(diào)用"這個詞并不常用,所以Java社區(qū)的人通常說"Java是傳值調(diào)用",這么說也沒錯,因為傳共享對象調(diào)用其實是傳值調(diào)用的一個特例。
值傳遞和共享對象傳遞的現(xiàn)象沖突嗎?
看到這里很多人可能會有一個疑問,既然共享對象傳遞是值傳遞的一個特例,那么為什么他們的現(xiàn)象是完全不同的呢?
難道值傳遞過程中,如果在被調(diào)方法中改變了值,也有可能會對調(diào)用者有影響嗎?那到底什么時候會影響什么時候不會影響呢?
其實是不沖突的,之所以會有這種疑惑,是因為大家對于到底是什么是"改變值"有誤解。
我們先回到上面的例子中來,看一下調(diào)用過程中實際上發(fā)生了什么?
在參數(shù)傳遞的過程中,實際參數(shù)的地址0X1213456
被拷貝給了形參。這個過程其實就是值傳遞,只不過傳遞的值得內(nèi)容是對象的應(yīng)用。
那為什么我們改了user中的屬性的值,卻對原來的user產(chǎn)生了影響呢?
其實,這個過程就好像是:你復(fù)制了一把你家里的鑰匙給到你的朋友,他拿到鑰匙以后,并沒有在這把鑰匙上做任何改動,而是通過鑰匙打開了你家里的房門,進到屋里,把你家的電視給砸了。
這個過程,對你手里的鑰匙來說,是沒有影響的,但是你的鑰匙對應(yīng)的房子里面的內(nèi)容卻是被人改動了。
也就是說,Java對象的傳遞,是通過復(fù)制的方式把引用關(guān)系傳遞了,如果我們沒有改引用關(guān)系,而是找到引用的地址,把里面的內(nèi)容改了,是會對調(diào)用方有影響的,因為大家指向的是同一個共享對象。
那么我們改變一下pass方法:
public void pass(User user) { user = new User(); user.setName("hollischuang"); System.out.println("print in pass , user is " + user); }
再看一下整個過程中發(fā)生了什么:
這個過程,就好像你復(fù)制了一把鑰匙給到你的朋友,你的朋友拿到你給他的鑰匙之后,找個鎖匠把他修改了一下,他手里的那把鑰匙變成了開他家鎖的鑰匙。這時候,他打開自己家,就算是把房子點了,對你手里的鑰匙,和你家的房子來說都是沒有任何影響的。
所以,Java中的對象傳遞,如果是修改引用,是不會對原來的對象有任何影響的,但是如果直接修改共享對象的屬性的值,是會對原來的對象有影響的。
4、總結(jié)
我們知道,編程語言中需要進行方法間的參數(shù)傳遞,這個傳遞的策略叫做求值策略。
在程序設(shè)計中,求值策略有很多種,比較常見的就是值傳遞和引用傳遞。還有一種值傳遞的特例——共享對象傳遞。
值傳遞和引用傳遞最大的區(qū)別是傳遞的過程中有沒有復(fù)制出一個副本來,如果是傳遞副本,那就是值傳遞,否則就是引用傳遞。
在Java中,其實是通過值傳遞實現(xiàn)的參數(shù)傳遞,只不過對于Java對象的傳遞,傳遞的內(nèi)容是對象的引用。
我們可以總結(jié)說,Java中的求值策略是共享對象傳遞,這是完全正確的。
但是,為了讓大家都能理解你說的,我們說Java中只有值傳遞,只不過傳遞的內(nèi)容是對象的引用。這也是沒毛病的。
但是,絕對不能認為Java中有引用傳遞。
到此這篇關(guān)于帶你詳細了解Java值傳遞和引用傳遞的文章就介紹到這了,更多相關(guān)Java值傳遞和引用傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JAVA把結(jié)果保留兩位小數(shù)的3種方法舉例
在寫程序的時候,有時候可能需要設(shè)置小數(shù)的位數(shù),所以下面這篇文章主要給大家介紹了關(guān)于JAVA把結(jié)果保留兩位小數(shù)的3種方法,文章通過代碼介紹的非常詳細,需要的朋友可以參考下2024-08-08Java編程通過匹配合并數(shù)據(jù)實例解析(數(shù)據(jù)預(yù)處理)
這篇文章主要介紹了Java編程通過匹配合并數(shù)據(jù)實例解析(數(shù)據(jù)預(yù)處理),分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-01-01用SpringBoot框架來接收multipart/form-data文件方式
這篇文章主要介紹了用SpringBoot框架來接收multipart/form-data文件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02