淺談Java到底是值傳遞還是引用傳遞呢
一、前言
最近在看Java核心卷一,也就是這本書:
在這本書里面也看到了這個(gè)問(wèn)題,Java是值傳遞還是引用傳遞,這個(gè)問(wèn)題其實(shí)也是很有意思的,之前也看到過(guò)這個(gè)問(wèn)題,但是只是依稀記得是值傳遞,而且網(wǎng)上也有在討論這個(gè)問(wèn)題的。所以就先說(shuō)結(jié)論吧:是值傳遞。
二、值傳遞與引用傳遞
既然討論是值傳遞還是引用傳遞,那肯定是要知道啥是值傳遞、引用傳遞的。
值傳遞:是指在調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)復(fù)制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對(duì)參數(shù)進(jìn)行修改,將不會(huì)影響到實(shí)際參數(shù)。
引用傳遞:是指在調(diào)用函數(shù)時(shí)將實(shí)際參數(shù)的地址直接傳遞到函數(shù)中,那么在函數(shù)中對(duì)參數(shù)所進(jìn)行的修改,將影響到實(shí)際參數(shù)。
所以我們就可以做個(gè)簡(jiǎn)單的比較:
值傳遞 | 引用傳遞 | |
將參數(shù)復(fù)制一份傳遞過(guò)去 | 將參數(shù)的實(shí)際地址傳遞過(guò)去 | |
不會(huì)影響到實(shí)際參數(shù) | 會(huì)影響到實(shí)際參數(shù) |
我們?cè)诜椒ㄖ校瑐鬟f參數(shù)類型有兩種:基本數(shù)據(jù)類型(數(shù)字、布爾)以及對(duì)象引用這兩種,所以我們就從這兩種類型進(jìn)行分析。
三、基本數(shù)據(jù)類型
以數(shù)字int為例:
public class Test { public static void main(String[] args) { Test test=new Test(); int i=1; test.incr(i); System.out.println("main中i的值大小為"+i); } public void incr(int i){ i=i+1; System.out.println("incr中i為"+i); } }
main方法中的結(jié)果要么為1,要么為2,如果還是1的話,那么很大可能就是值傳遞,我們看下輸出結(jié)果:
incr中i為2
main中i的值大小為1
可以看到,main方法中的值仍為1,我們來(lái)看下這個(gè)的過(guò)程是怎么樣的:
incr方法中雖然對(duì)i的值進(jìn)行了加一操作,但是他只是將值復(fù)制了一份,incr方法執(zhí)行完畢之后,就會(huì)被處理掉,并沒(méi)有改掉原先的值,所以才會(huì)在main方法中打印出i還是原先的值。
四、對(duì)象引用
基本數(shù)據(jù)類型其實(shí)比較好解釋,對(duì)象引用其實(shí)還是有那么一點(diǎn)迷惑性的,因?yàn)橛械娜丝梢哉J(rèn)為對(duì)象引用是引用傳遞,他可以向方法中傳遞一個(gè)對(duì)象,然后在子方法中修改對(duì)象的值,就比如下面的這個(gè)例子:
例子一:
public class Test { public static void main(String[] args) { Test test=new Test(); Student s1=new Student(); s1.setId(1); test.changeId(s1); System.out.println("main中的s1id是"+s1.getId()); } public void changeId(Student student){ student.setId(2); System.out.println("changeId中的id為"+student.getId()); } } class Student{ private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } }
一個(gè)很簡(jiǎn)單的例子,創(chuàng)建個(gè)student對(duì)象,只有id這一個(gè)字段,將student對(duì)象傳遞到子方法中,執(zhí)行結(jié)果會(huì)是什么呢?
changeId中的id為2
main中的s1id是2
可以看到阿,main方法與changeId方法中,他們最后的id都是2,所以有的人就會(huì)認(rèn)為,修改了對(duì)象中的值,所以是值傳遞。
其實(shí)我們看上面值傳遞與引用傳遞的概念,引用傳遞是傳遞的地址,那么我們就假設(shè)對(duì)象引用是引用傳遞方式,那么我傳遞進(jìn)去兩個(gè)對(duì)象,交換他們的位置是可以改變他們的指向的,接下來(lái)我們就來(lái)看一下會(huì)不會(huì)改變:
例子二:
package com.dong.No2; public class Test { public static void main(String[] args) { Test test=new Test(); Student s1=new Student(); Student s2=new Student(); s1.setId(1); s2.setId(2); test.changeId2(s1,s2); System.out.println("main中的s1id是"+s1.getId()+","+"s2id是"+s2.getId()); } public void changeId2(Student s1,Student s2){ Student s3=s1; s1=s2; s2=s3; System.out.println("changeId2中的s1id是"+s1.getId()+",s2id是"+s2.getId()); } } class Student{ private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } }
他的執(zhí)行結(jié)果:
changeId2中的s1id是2,s2id是1
main中的s1id是1,s2id是2
我們發(fā)現(xiàn),這個(gè)在子方法中,對(duì)象的值是改變了,但是main方法中的值還是原先的樣子,那這樣就不符合引用傳遞了,因?yàn)樗鋵?shí)并沒(méi)有改變?cè)鹊膶?duì)象。
如果我們以值傳遞的觀點(diǎn)來(lái)解釋,那么就可以說(shuō)的通了,我們傳入的兩個(gè)參數(shù)s1、s2在傳遞過(guò)去后,會(huì)復(fù)制一份為s1復(fù)制、s2復(fù)制,然后在子方法中,是對(duì)這兩個(gè)復(fù)制過(guò)后的對(duì)象進(jìn)行的操作,執(zhí)行完之后,這些復(fù)制的對(duì)象就會(huì)被回收,所以就出現(xiàn)了我們?cè)谥鞣椒ㄖ校吹竭@兩個(gè)對(duì)象的值是沒(méi)有改變的。
事實(shí)上也是如此,我們可以同樣來(lái)解釋例子一種,為啥傳入了對(duì)象,但是主方法中的值卻改變了。
我們知道對(duì)象這些都是在堆中存儲(chǔ)的,我們?cè)谙蚍椒ㄖ袀鬟f的,實(shí)際上是這個(gè)對(duì)象在堆中的地址,我們傳遞的對(duì)象,實(shí)際上就是傳遞的對(duì)象的地址:
因?yàn)閟1與s1復(fù)制都是指向的ox123456,s1復(fù)制改變了值,那么s1看到的值也就發(fā)生了改變,即使是s1復(fù)制最后被回收,ox123456的改變不會(huì)恢復(fù)。
五、結(jié)論
所以Java中的傳遞只有值傳遞而沒(méi)有引用傳遞,只不過(guò)傳遞為基本數(shù)據(jù)類型的話,是復(fù)制的數(shù)值,而對(duì)象類型的話,則是復(fù)制的對(duì)象存放地址。
到此這篇關(guān)于淺談Java到底是值傳遞還是引用傳遞呢的文章就介紹到這了,更多相關(guān)Java值傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot項(xiàng)目中使用OkHttp獲取IP地址的示例代碼
OkHttp?是一個(gè)由?Square?開(kāi)發(fā)的高效、現(xiàn)代的?HTTP?客戶端庫(kù),用于?Android?和?Java?應(yīng)用程序,它支持?HTTP/2?和?SPDY?等現(xiàn)代網(wǎng)絡(luò)協(xié)議,并提供了多種功能和優(yōu)化,本文給大家介紹了SpringBoot項(xiàng)目中如何獲取IP地址,需要的朋友可以參考下2024-08-08淺析從同步原語(yǔ)看非阻塞同步以及Java中的應(yīng)用
非阻塞同步是基于沖突檢測(cè)的樂(lè)觀并發(fā)策略,這種樂(lè)觀的并發(fā)策略使得很多線程不需要因?yàn)楦?jìng)爭(zhēng)失敗直接掛起,這種同步措施稱為非阻塞同步。下面我們就從硬件原語(yǔ)開(kāi)始了解非阻塞同步,并看一看在Java中非阻塞同步的一些應(yīng)用2021-06-06java IO實(shí)現(xiàn)電腦搜索、刪除功能的實(shí)例
下面小編就為大家?guī)?lái)一篇java IO實(shí)現(xiàn)電腦搜索、刪除功能的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12Java使用策略模式實(shí)現(xiàn)聚石塔接口調(diào)用的問(wèn)題
這篇文章主要介紹了Java使用策略模式實(shí)現(xiàn)聚石塔接口調(diào)用,為了避免多重判斷,而且有更好的擴(kuò)展性,首選了策略模式來(lái)實(shí)現(xiàn),具體解決方法跟隨小編一起看看吧2021-12-12Spring事務(wù)相關(guān)問(wèn)題解決方案
這篇文章主要介紹了Spring事務(wù)相關(guān)問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02AndroidQ沙盒機(jī)制之分區(qū)存儲(chǔ)適配
這篇文章主要介紹了AndroidQ沙盒機(jī)制之分區(qū)存儲(chǔ)適配,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06解決springboot中mongodb不啟動(dòng)及Dao不能被掃描到的問(wèn)題
這篇文章主要介紹了解決springboot中mongodb不啟動(dòng)及Dao不能被掃描到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05