您好,登錄后才能下訂單哦!
怎么在Java中實現值傳遞和引用傳遞?相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
Java的特點有哪些 1.Java語言作為靜態面向對象編程語言的代表,實現了面向對象理論,允許程序員以優雅的思維方式進行復雜的編程。 2.Java具有簡單性、面向對象、分布式、安全性、平臺獨立與可移植性、動態性等特點。 3.使用Java可以編寫桌面應用程序、Web應用程序、分布式系統和嵌入式系統應用程序等。
值傳遞(pass by value)是指在調用函數時將實際參數復制一份傳遞到函數中,這樣在函數中如果對參數進行修改,將不會影響到實際參數。
引用傳遞(pass by reference)是指在調用函數時將實際參數的地址直接傳遞到函數中,那么在函數中對參數所進行的修改,將影響到實際參數。
錯誤理解一:值傳遞和引用傳遞,區分的條件是傳遞的內容,如果是個值,就是值傳遞。如果是個引用,就是引用傳遞
錯誤理解二:Java是引用傳遞。
錯誤理解三:傳遞的參數如果是普通類型,那就是值傳遞,如果是對象,那就是引用傳遞。
我們說當進行方法調用的時候,需要把實際參數傳遞給形式參數,那么傳遞的過程中到底傳遞的是什么東西呢?
這其實是程序設計中求值策略(Evaluation strategies)的概念。
在計算機科學中,求值策略是確定編程語言中表達式的求值的一組(通常確定性的)規則。求值策略定義何時和以何種順序求值給函數的實際參數、什么時候把它們代換入函數、和代換以何種形式發生。
求值策略分為兩大基本類,基于如何處理給函數的實際參數,分為嚴格的和非嚴格的。
在“嚴格求值”中,函數調用過程中,給函數的實際參數總是在應用這個函數之前求值。多數現存編程語言對函數都使用嚴格求值。所以,我們本文只關注嚴格求值。
在嚴格求值中有幾個關鍵的求值策略是我們比較關心的,那就是傳值調用(Call by value)、傳引用調用(Call by reference)以及傳共享對象調用(Call by sharing)
1.傳值調用(值傳遞):在傳值調用中,實際參數先被求值,然后其值通過復制,在傳遞給被調函數的形式參數。因為形式參數拿到的只是一個"局部拷貝",所以如果在被調函數中改變了形式參數的值,并不會改變實際參數的值。
2.傳引用調用(引用傳遞)在傳引用調用中,傳遞給函數的是它的實際參數的隱式引用而不是實參的拷貝。因為傳遞的是引用,所以,如果在被調函數中改變了形式參數的值,改變對于調用者來說是可見的。
3.傳共享對象調用(共享對象傳遞)傳共享對象調用中,先獲取到實際參數的地址,然后將其復制,并把該地址的拷貝傳遞給被調函數的形式參數。因為參數的地址都指向同一個對象,所以我們也稱之為"傳共享對象",所以,如果在被調函數中改變了形式參數的值,調用者是可以看到這種變化的。
不知道大家有沒有發現,其實傳共享對象調用和傳值調用的過程幾乎是一樣的,都是進行"求值"、"拷貝"、"傳遞"。你品,你細品。
但是,傳共享對象調用和內傳引用調用的結果又是一樣的,都是在被調函數中如果改變參數的內容,那么這種改變也會對調用者有影響。你再品,你再細品。
那么,共享對象傳遞和值傳遞以及引用傳遞之間到底有很么關系呢?
對于這個問題,我們應該關注過程,而不是結果,因為傳共享對象調用的過程和傳值調用的過程是一樣的,而且都有一步關鍵的操作,那就是"復制",所以,通常我們認為傳共享對象調用是傳值調用的特例
我們先把傳共享對象調用放在一邊,我們再來回顧下傳值調用和傳引用調用的主要區別:
傳值調用是指在調用函數時將實際參數復制
一份傳遞到函數中,傳引用調用是指在調用函數時將實際參數的引用直接
傳遞到函數中。
前面我們介紹過了傳值調用、傳引用調用以及傳值調用的特例傳共享對象調用,那么,Java中是采用的哪種求值策略呢?
很多人說Java中的基本數據類型是值傳遞的,這個基本沒有什么可以討論的,普遍都是這樣認為的。
但是,有很多人卻誤認為Java中的對象傳遞是引用傳遞。之所以會有這個誤區,主要是因為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方法后,在方法內改變了其內容,最終調用方main方法中的對象也變了。
所以,很多人說,這和引用傳遞的現象是一樣的,就是在方法內改變參數的值,會影響到調用方。
但是,其實這是走進了一個誤區。
其實Java中使用的求值策略就是傳共享對象調用,也就是說,Java會將對象的地址的拷貝傳遞給被調函數的形式參數。只不過"傳共享對象調用"這個詞并不常用,所以Java社區的人通常說"Java是傳值調用",這么說也沒錯,因為傳共享對象調用其實是傳值調用的一個特例。
值傳遞和共享對象傳遞的現象沖突嗎?
看到這里很多人可能會有一個疑問,既然共享對象傳遞是值傳遞的一個特例,那么為什么他們的現象是完全不同的呢?
難道值傳遞過程中,如果在被調方法中改變了值,也有可能會對調用者有影響嗎?那到底什么時候會影響什么時候不會影響呢?
其實是不沖突的,之所以會有這種疑惑,是因為大家對于到底是什么是"改變值"有誤解。
我們先回到上面的例子中來,看一下調用過程中實際上發生了什么?
在參數傳遞的過程中,實際參數的地址0X1213456
被拷貝給了形參。這個過程其實就是值傳遞,只不過傳遞的值得內容是對象的應用。
那為什么我們改了user中的屬性的值,卻對原來的user產生了影響呢?
其實,這個過程就好像是:你復制了一把你家里的鑰匙給到你的朋友,他拿到鑰匙以后,并沒有在這把鑰匙上做任何改動,而是通過鑰匙打開了你家里的房門,進到屋里,把你家的電視給砸了。
這個過程,對你手里的鑰匙來說,是沒有影響的,但是你的鑰匙對應的房子里面的內容卻是被人改動了。
也就是說,Java對象的傳遞,是通過復制的方式把引用關系傳遞了,如果我們沒有改引用關系,而是找到引用的地址,把里面的內容改了,是會對調用方有影響的,因為大家指向的是同一個共享對象。
那么我們改變一下pass方法:
public void pass(User user) { user = new User(); user.setName("hollischuang"); System.out.println("print in pass , user is " + user); }
再看一下整個過程中發生了什么:
這個過程,就好像你復制了一把鑰匙給到你的朋友,你的朋友拿到你給他的鑰匙之后,找個鎖匠把他修改了一下,他手里的那把鑰匙變成了開他家鎖的鑰匙。這時候,他打開自己家,就算是把房子點了,對你手里的鑰匙,和你家的房子來說都是沒有任何影響的。
所以,Java中的對象傳遞,如果是修改引用,是不會對原來的對象有任何影響的,但是如果直接修改共享對象的屬性的值,是會對原來的對象有影響的。
看完上述內容,你們掌握怎么在Java中實現值傳遞和引用傳遞的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。