Java基礎(chǔ)之值傳遞和引用傳遞

前言

值傳遞和引用傳遞是java基礎(chǔ)知識中一個(gè)比較重要的概念,如果對這個(gè)概念理解不清的話,可能就會造成我們的代碼出現(xiàn)“對象中的值被無故改變了”這種問題。本篇文章將針對這兩個(gè)概念進(jìn)行介紹和講解,希望對各位讀者有所幫助。

(一)值傳遞的例子

我們先來看下面這個(gè)例子,判斷一下最終的輸出會是什么?

public class Test {
    public static void main(String[] args) {
        int i = 10;
        changeValue(i);
        System.out.println(i);
    }
    
    private static void changeValue(int i){
        i = 20;
    }
}

最終的執(zhí)行結(jié)果為10,這個(gè)結(jié)果似乎很好理解,調(diào)用changeValue方法時(shí),我們相當(dāng)于是將10作為入?yún)髁诉M(jìn)去,賦值給了changeValue方法的形參i,至于形參i后續(xù)的值發(fā)生變化,是不會影響到main方法中的i的。而上面例子中調(diào)用方法時(shí)只涉及到基本數(shù)據(jù)類型的傳遞,這種傳遞方式通常也被叫做值傳遞。

代碼執(zhí)行結(jié)果

(二)引用傳遞的例子1

我們再來看下面這個(gè)例子,調(diào)用的方法入?yún)⒏某闪藢ο?,再來看看最終的輸出結(jié)果會是什么

public class Test {

    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.setName("aaa");
        changeValue(test);
        System.out.println(test.getName());
    }

    private static void changeValue(Test test){
        test.setName("bbb");
    }
}

最終的輸出結(jié)果如下,答案為bbb,可能會讓初學(xué)者感到不解,為何相似的操作得到的結(jié)果卻不同。我們在方法中修改了Test對象的屬性,為什么會影響到main方法中Test對象的值呢?

代碼執(zhí)行結(jié)果

其實(shí)答案并不難理解,我們知道對于引用數(shù)據(jù)類型,這類對象的值并不會放在棧中,而是會單獨(dú)放在堆內(nèi)存中,而棧中對象的值為實(shí)際對象在堆內(nèi)存中的地址值(類似:0x123123123)。當(dāng)我們調(diào)用changeValue(Test test)方法時(shí),會將test對象在內(nèi)存中的引用傳遞了進(jìn)去。也就是說,此時(shí)main方法中的test和changeValue方法中的形參test都指向了堆中的同一個(gè)對象。而changeValue方法在調(diào)用的過程中修改了對象在堆內(nèi)存中的屬性,main方法中的test變量也就會同樣受到影響。
在這個(gè)例子中,我們傳遞給方法的參數(shù)是一個(gè)引用數(shù)據(jù)類型的變量,這種傳遞方式通常也被稱為引用傳遞。
image.png

(三)引用傳遞的例子2

我們再來看下面一個(gè)引用傳遞相關(guān)的例子,判斷一下最終輸出的值是什么

public class Test {

    String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.setName("aaa");
        changeValue(test);
        System.out.println(test.getName());
    }

    private static void changeValue(Test test){
        Test test1 = new Test();
        test1.setName("bbb");
        test = test1;
    }
}

這次的執(zhí)行結(jié)果為aaa。原因也很好理解,changeValue方法中,我們只是對test形參的指向進(jìn)行了變化,并不涉及對原Test對象的修改。

代碼執(zhí)行結(jié)果

簡單的內(nèi)存分析圖

值傳遞和引用傳遞的本質(zhì)

本質(zhì)上來說,所謂的引用傳遞實(shí)質(zhì)上也是值傳遞,只是傳遞的值是對象在內(nèi)存中的地址值而已。個(gè)人認(rèn)為,單純記傳入的值是基本數(shù)據(jù)類型還是引用類型并不是理解這個(gè)知識的好方法。更好的方法是理解調(diào)用方法傳入?yún)?shù)時(shí),代碼做了什么。以第二個(gè)例子為例,我們可以把執(zhí)行過程寫成下面的偽代碼:
(值傳遞的過程其實(shí)就只是一個(gè)簡單的值拷貝,然后賦值給方法的形參而已)

        Test test = new Test();
        test.setName("aaa");
        //下面是changeValue(test)執(zhí)行的步驟
        {
            // 新建了一個(gè)Test類型的變量test1, 且把test的值賦給了變量test1
            Test test1 = test;
            // test的值本質(zhì)上就是一個(gè)地址值
            test1.setName("bbb");
        }
        System.out.println(test.getName());

而原對象到底會不會被修改,最為關(guān)鍵的地方在于是否改動了原對象在內(nèi)存中的屬性值,形參單純的修改對象指向并不會對原對象造成影響。正因?yàn)閭鬟f對象時(shí)傳遞的是對象在內(nèi)存中的地址值,所以我們在進(jìn)行引用傳遞的時(shí)候,一定要注意,不要輕易修改原對象的屬性。如果涉及到修改的操作,建議深拷貝一份對象給形參之后,再進(jìn)行對象屬性的修改操作。

小結(jié)

至此,對于值傳遞和引用傳遞的概念就介紹到這里,深刻理解調(diào)用方法時(shí)的賦值過程,相信可以幫助各位初學(xué)者避開很多坑。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容