關(guān)于Java是值傳遞還是引用傳遞

先說結(jié)論给僵,Java是值傳遞

很多小伙伴認為:值傳遞和引用傳遞區(qū)分的條件就是毫捣,如果方法的實參傳遞的是一個值,則是值傳遞帝际,如果傳遞的是一個引用蔓同,則是引用傳遞,或者說蹲诀,如果傳遞的是一個基本數(shù)據(jù)類型斑粱,則是值傳遞,如果傳遞的是一個對象脯爪,則是引用傳遞则北。
但是這種觀點是錯誤的矿微,首先讓我們來看一下值傳遞和引用傳遞的定義:

值傳遞是指在調(diào)用函數(shù)時將實際參數(shù)復(fù)制一份傳遞到函數(shù)中,這樣在函數(shù)中如果對這個參數(shù)進行修改尚揣,將不會影響到實際參數(shù)
引用傳遞是指在調(diào)用函數(shù)時將實際參數(shù)的地址直接傳遞到函數(shù)中涌矢,那么在函數(shù)中對該參數(shù)所進行的修改,將影響到實際參數(shù)

有了定義快骗,我們可以做實驗了:

public static void main(String[] args) {
        Test test = new Test();
        int value = 100;
        test.alterAndPrint(value);
        System.out.println("main函數(shù)中value的值為: " + value);
    }

    public void alterAndPrint(int i) {
        i = 500;
        System.out.println("alterAndPrint函數(shù)中value的值為: " + i);
    }

這段代碼的輸出結(jié)果為:

alterAndPrint函數(shù)中value的值為: 500
main函數(shù)中value的值為: 100

有了這個結(jié)果娜庇,很多小伙伴就覺得可以下結(jié)論了:Java是值傳遞,但是可能會有人說不對方篮,然后擺出另一個實驗結(jié)果:

public static void main(String[] args) {
        Test test = new Test();
        Person person = new Person();
        person.setName("zhangsan");
        person.setAge(18);
        test.alterAndPrint(person);
        System.out.println("main函數(shù)中的Person為: " + person);
    }

    public void alterAndPrint(Person p) {
        p.setName("lisi");
        p.setAge(24);
        System.out.println("alterAndPrint函數(shù)中的Person為: " + p);
    }

結(jié)果為:

alterAndPrint函數(shù)中的Person為: Person{name='lisi', age=24}
main函數(shù)中的Person為: Person{name='lisi', age=24}

然后發(fā)現(xiàn)名秀,實參的內(nèi)容發(fā)生了改變,于是就得出結(jié)論恭取,Java在傳遞基本數(shù)據(jù)類型的時候是值傳遞泰偿,在傳遞對象的時候是引用傳遞熄守,但是還有一種特殊情況:

public static void main(String[] args) {
        Test test = new Test();
        String s = "Java";
        test.alterAndPrint(s);
        System.out.println("main函數(shù)中的String為: " + str);
    }

    public void alterAndPrint(String str) {
        str = "Golang";
        System.out.println("alterAndPrint函數(shù)中的String為: " + str);
    }

這段代碼結(jié)果為:

alterAndPrint函數(shù)中的String為: Golang
main函數(shù)中的String為: Java

好蜈垮,走到這一步,已經(jīng)有很多小伙伴開始疑惑了裕照,不是傳遞對象的時候是引用傳遞嗎攒发,為什么又變成值傳遞了。
其實晋南,概念上是沒有問題的惠猿,但是我們的實驗方法出了些許問題,我們再來回看定義:

值傳遞是指在調(diào)用函數(shù)時將實際參數(shù)復(fù)制一份傳遞到函數(shù)中负间,這樣在函數(shù)中如果對這個參數(shù)進行修改偶妖,將不會影響到實際參數(shù)
引用傳遞是指在調(diào)用函數(shù)時將實際參數(shù)的地址直接傳遞到函數(shù)中,那么在函數(shù)中對該參數(shù)所進行的修改政溃,將影響到實際參數(shù)

重點區(qū)分一下這兩個的區(qū)別就是:

值傳遞需要復(fù)制一份參數(shù)趾访,且函數(shù)中對參數(shù)的改變不會影響到原參數(shù)
引用傳遞不需要復(fù)制,且函數(shù)中對該參數(shù)的改變會影響到原參數(shù)

在上面的Person那個例子中董虱,我們改變的是參數(shù)的內(nèi)容扼鞋,而不是參數(shù)本身,所以說本身方法就錯了愤诱,正常的實驗方法云头,也即是真正地去改變參數(shù)應(yīng)該是這樣:

public static void main(String[] args) {
       Test test = new Test();
       Person person = new Person();
       person.setName("zhangsan");
       person.setAge(18);
       test.alterAndPrint(person);
       System.out.println("main函數(shù)中的Person為: " + person);
   }

   public void alterAndPrint(Person p) {
       p = new Person();
       p.setName("lisi");
       p.setAge(24);
       System.out.println("alterAndPrint函數(shù)中的Person為: " + p);
   }

輸出結(jié)果為:

alterAndPrint函數(shù)中的Person為: Person{name='lisi', age=24}
main函數(shù)中的Person為: Person{name='zhangsan', age=18}

配合圖來理解:



在main函數(shù)中我們new了一個person對象,并且給它的name和age屬性賦值淫半,person就擁有了這個內(nèi)存的地址溃槐,也即是0x777999,當(dāng)調(diào)用alterAndPrint方法時科吭,將實參person傳給形參p竿痰,p也指向了這一塊地址脆粥,執(zhí)行alterAndPrint方法的內(nèi)容時,對參數(shù)進行修改影涉,也即p = new Person()变隔,這行代碼會在堆區(qū)開辟一段新的內(nèi)存,后面對p的更改都不會影響到0x777999這塊內(nèi)存的數(shù)據(jù)蟹倾,
上面這種方式是什么傳遞匣缘,反正肯定不是引用傳遞,因為如果是引用傳遞的話鲜棠,在p = new Person()這一串代碼執(zhí)行完后肌厨,實際的參數(shù)的引用也應(yīng)該指向0x777555這一塊內(nèi)存,但是我們發(fā)現(xiàn)并沒有這樣

通過上面的定義我們可以知道豁陆,這是把實際參數(shù)的引用地址復(fù)制了一份柑爸,傳遞給了形式參數(shù),所以盒音,上面的參數(shù)其實是值傳遞表鳍,把實參對象引用的地址當(dāng)做值傳遞給了形式參數(shù)。

所以祥诽,要區(qū)分值傳遞和引用傳遞并不是靠辨別傳遞的內(nèi)容譬圣,而是有沒有將實參復(fù)制一份副本傳遞給形參,如果傳遞的是地址雄坪,那么就要看這個地址是否發(fā)生改變厘熟,而不是看地址對應(yīng)的對象的內(nèi)容是否發(fā)生改變
那為什么String的那個例子會出現(xiàn)另一種情況呢?
因為str = "Golang"這一句代碼改變了引用的地址维哈,new了一個新的String绳姨,也即等價于str=new String("Golang'),而并沒有改變原實參的引用地址


所以說阔挠,Java方法之間其實還是值傳遞的飘庄,對于基本數(shù)據(jù)類型,值的內(nèi)容是數(shù)值谒亦,對于對象參數(shù)竭宰,值的內(nèi)容是對象的引用。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末份招,一起剝皮案震驚了整個濱河市切揭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锁摔,老刑警劉巖廓旬,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡孕豹,警方通過查閱死者的電腦和手機涩盾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來励背,“玉大人春霍,你說我怎么就攤上這事∫睹迹” “怎么了址儒?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衅疙。 經(jīng)常有香客問我莲趣,道長,這世上最難降的妖魔是什么饱溢? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任喧伞,我火速辦了婚禮,結(jié)果婚禮上绩郎,老公的妹妹穿的比我還像新娘潘鲫。我一直安慰自己,他們只是感情好嗽上,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布次舌。 她就那樣靜靜地躺著熄攘,像睡著了一般兽愤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挪圾,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天浅萧,我揣著相機與錄音,去河邊找鬼哲思。 笑死洼畅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的棚赔。 我是一名探鬼主播帝簇,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼靠益!你這毒婦竟也來了丧肴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤胧后,失蹤者是張志新(化名)和其女友劉穎芋浮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體壳快,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡纸巷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年镇草,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘤旨。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡梯啤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出存哲,到底是詐尸還是另有隱情条辟,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布宏胯,位于F島的核電站羽嫡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏肩袍。R本人自食惡果不足惜杭棵,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望氛赐。 院中可真熱鬧魂爪,春花似錦、人聲如沸艰管。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牲芋。三九已至撩笆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缸浦,已是汗流浹背夕冲。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留裂逐,地道東北人歹鱼。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像卜高,于是被迫代替她去往敵國和親弥姻。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

推薦閱讀更多精彩內(nèi)容