188W+程序員關注過的問題:Java究竟是值傳遞仍是引用傳遞?

在逛 Stack Overflow 的時候,發現了一些訪問量像阿爾卑斯山同樣高的問題,好比說這個:Java 究竟是值傳遞仍是引用傳遞?訪問量足足有 188萬+,這不得了啊!說明有不少不少的程序員被這個問題困擾過。實話實說吧,就是其中之一。html

來回顧一下提問者的問題:java

我一直認爲 Java 是按引用傳遞的,可是我看一些博客上說不是的。我就納悶了,Java 究竟是值傳遞仍是引用傳遞?值傳遞和引用傳遞有什麼區別呢?程序員

若是你也曾被這個問題困擾過,或者正在被困擾,就請隨我一塊兒來梳理一下問題的答案。打怪進階嘍!bash

0一、值傳遞和引用傳遞

什麼是值傳遞,什麼是引用傳遞?咱們須要先把這兩個定義搞清楚,才能搞清楚 Java 是按值傳遞仍是按引用傳遞。微信

值傳遞(pass by value)是指在調用方法時將實參複製一份傳遞到方法中,這樣當方法對形參進行修改時不會影響到實參。
引用傳遞(pass by reference)是指在調用方法時將實參的地址直接傳遞到方法中,那麼在方法中對形參所進行的修改,將影響到實參。this

上面是比較官方的定義,讀起來難免生硬。在我看來,值傳遞和引用傳遞的關鍵區別有兩點:spa

1)調用方法時有沒有對實參進行復制。code

2)方法內對形參的修改會不會影響到實參。cdn

what?值傳遞和引用傳遞尚未搞清楚,又來兩個新名詞:實參和形參。別急,別急。htm

0二、實參和形參

實參和形參理解起來比值傳遞和引用傳遞容易的多,前者就好像是一元一次方程,後者就像是一元二次方程。

形參:定義方法名和方法體的時候使用的參數,目的是用來接收調用該方法時傳入的參數。
實參:在調用有參方法時傳入的參數,方法名後面的括號中的參數一般被稱爲「實參」。

你們應該都寫過「hello world」程序了,就像下面這樣。

public class Cmower {
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}
複製代碼

其中 args 就至關因而形參,而字符串「hello world」就至關因而實參。若是以爲這個例子不容易理解,那再來看一個。

public class Cmower {
    public static void main(String[] args) {
        Cmower cmower = new Cmower();
        cmower.sop("沉默王二");
    }

    public void sop(String name) {
        System.out.println("hello " + name);
    }
}
複製代碼

其中「沉默王二」爲實參;有參方法 sop(String name) 中的 name 爲形參。形參就好像實參與被調用方法之間的一個橋樑,不然調用者無法傳遞參數,被調用的方法沒法接收參數。

0三、基本類型是值傳遞的

Java 中的數據類型能夠分爲兩種,一種是基本類型,一種是引用類型。我相信你們在看本篇文章以前,就可以達成這樣一個共識:基本類型是值傳遞的。這一點毫無疑問。

public class Cmower {
    public static void main(String[] args) {
        Cmower cmower = new Cmower();
        int age = 18;
        cmower.sop(age);
        System.out.println("main 中的 age " + age);
    }

    public void sop(int age) {
        age = 28;
        System.out.println("sop 中的 age " + age);
    }
}
複製代碼

上面這段代碼中,sop() 方法的實參 age 爲 18,儘管 sop() 方法的形參被修改成 28,但並不會影響實參的值。這一點能夠從輸出結果中加以證實。

sop 中的 age 28
main 中的 age 18
複製代碼

具體的執行過程以下圖所示。

0四、引用類型是值傳遞嗎?

你們之因此不肯定 Java 是值傳遞的仍是引用傳遞的,緣由就出在這個引用類型上面。單從字面的意思上就容易搞混:引用類型不是引用傳遞難道仍是值傳遞?

public class Cmower {
    private String name;

    public String getName() {
        return name;
    }

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

    public static void main(String[] args) {
        Cmower cmower = new Cmower();
        cmower.setName("沉默王二");
        cmower.sop(cmower);
        System.out.println("main 中的 cmower " + cmower.getName());
    }

    public void sop(Cmower cmower) {
        cmower.setName("沉默王三");
        System.out.println("sop 中的 cmower " + cmower.getName());
    }
}
複製代碼

main() 方法中,咱們經過 new 關鍵字建立了一個對象 cmower,並將其 name 屬性設置爲「沉默王二」;而後將實參 cmower 傳遞給 sop() 方法,在 sop() 方法中將形參 cmower 的 name 屬性修改成「沉默王三」。輸出結果是什麼樣子呢?

sop 中的 cmower 沉默王三
main 中的 cmower 沉默王三
複製代碼

呀!實參 cmower 的屬性 name 居然不是「沉默王二」而是「沉默王三」了!看看,看看,Java 不是值傳遞吧?

別急別急。咱們在 main 方法中追加幾行代碼。

Cmower cmower = new Cmower();
cmower.setName("沉默王二");

Cmower old = cmower;
cmower.sop(cmower);
System.out.println("main 中的 cmower " + cmower.getName());

System.out.println(old == cmower);
複製代碼

old == cmower 會是 true 仍是 false 呢?閉上眼睛想想。若是實在是想不出,拋一枚硬幣吧,反正不是 true 就是 false。假如引用類型是引用傳遞的,根據引用傳遞的定義(形參的修改將會影響到實參),那麼結果必定就是 false。

咱們來看一下輸出結果:

sop 中的 cmower 沉默王三
main 中的 cmower 沉默王三
true
複製代碼

true?開什麼玩笑?

很差意思,沒有開玩笑。Java 的確是值傳遞的。只不過,引用類型在調用有參方法的時候,傳遞的是對象的引用,並非對象自己。而對象的引用在傳遞的過程當中並無發生改變,雖然對象自己發生了變化。能夠經過下面這幅圖感覺一下。

這下理解了吧?

0五、總結

來看下面這段代碼。

int age = 18;
String name = "沉默王二";
複製代碼

age 是基本類型,因此值就直接保存在變量中;而 name 是引用類型,變量中保存的只是對象的內存地址,這種變量通常稱之爲對象的引用。

基本類型做爲參數被傳遞時確定是值傳遞;引用類型做爲參數被傳遞時也是值傳遞,只不過「值」爲對應的引用。


好了各位讀者朋友們,以上就是本文的所有內容了。能看到這裏的都是最優秀的程序員,我必需要爲你們點個贊👍。若是以爲不過癮,還想看到更多,我再推薦幾篇給你們。

370W+程序員關注過的問題:如何比較 Java 的字符串? 250W+程序員關注過的問題:什麼是 NullPointerException? 50W+程序員關注過的問題:爲何會發生ArrayIndexOutOfBoundsException?

有收穫?就點贊、留言,讓更多的人看到這篇文章。

若是想要第一時間看到我更新的文章,能夠微信搜索「沉默王二」,關注個人公衆號,回覆「java」再送你一份精選電子書大禮包,包含這十年來我讀過的最優質的 Java 書籍。

相關文章
相關標籤/搜索