用最簡單的方式解釋 Java 是值傳遞還是引用傳遞

相關文章:

本文目標:去掉高大上的專有名詞,用最簡單的方式解釋“我這個 Java 方法到底傳遞的是啥”。

背景和其他(可跳過)

先用兩句“廢話”介紹一下背景,本段可直接跳過,昨天一做 C/C++ 好友想學習一下 Java,環境配置好了,IDEA 也裝好了,“HelloWorld”也擼出來了。但是在看到《Java 核心技術 卷 Ⅰ》時候對“Java 是值傳遞還是引用傳遞”提出了疑問。

首先這本書相關的描述過於複雜和囉嗦,反而對本來就帶着疑問去翻閱的人引入了很多新的概念,比如“按值調用”、“按引用調用”、“對象引用是按值傳遞的”,當然,這裏並不是說這本書不好,作爲一本專業書籍,理應用詞嚴謹,但是如果是帶着“ Java 是值傳遞還是引用傳遞”這個疑問去查看這本書,反而不一定能很快地得出結論,理解作者的本意。

所以本文的目標並不想去過多的比較描述什麼是“值傳遞”,什麼是“引用傳遞”,它們有什麼區別等等,因爲這些概念其實沒那麼大意義(Java 一大嘈點就是學院派風格嚴重),反而讓人難以理解更重要的內容,而更重要的是在平時擼碼的過程中能夠理解“我這個方法到底傳的是啥”

結論

先說結論:Java 傳遞的是值,如果是基本數據類型,這個值就是字面量的值,如果是引用數據類型,這個值就是地址(後續打算通過調試 OpenJDK 源碼進行證明)。那爲什麼是地址呢,其實可以猜想下,完全沒有必要對堆中的對象實例進行拷貝。

接下來就是舉幾個例子。

第一個例子,傳遞 int

/**
 * @author Dongguabai
 * @Description
 * @Date 創建於 2020-06-06 16:54
 */
public class PassTest2 {
    
    public static void main(String[] args) {
        int i = 10;
        System.out.println("before:" + i);
        updateInt(i);
        System.out.println("after:" + i);
    }

    private static void updateInt(int j) {
        j = 20;
    }
}

輸出結果:

before:10
after:10

在 Java 中,基本數據類型是直接存放在虛擬機棧(局部變量表)中,在調用 updateInt() 方法時會將 i 的值進行拷貝:

在這裏插入圖片描述

第二個例子:

public class PassTest {

    public static void main(String[] args) {
        User user1 = new User("zhangsan1");
        System.out.println(user1);
        updateUser(user1);
        System.out.println(user1);
    }

    public static void updateUser(User user2) {
        user2.setUsername("修改");
    }

}

輸出:

User{username='zhangsan1'}
User{username='修改'}

這時候發現原來的 user1 對象被更改了。再看第三個例子:

public class PassTest {

    public static void main(String[] args) {
        User user1 = new User("zhangsan1");
        User user2 = new User("zhangsan2");
        System.out.println(user1);
        System.out.println(user2);
        System.out.println("=================");
        swap(user1, user2);
        System.out.println(user1);
        System.out.println(user2);
    }

    public static void swap(User x, User y) {
        User temp = x;
        x = y;
        y = temp;
    }

}

輸出:

User{username='zhangsan1'}
User{username='zhangsan2'}
=================
User{username='zhangsan1'}
User{username='zhangsan2'}

發現並未更改原始值。

先分析第二個例子:
在這裏插入圖片描述
user2 對象拷貝了 user1 對象的地址,這時候 user2 和 user1 指向的是堆中同一塊內存(這裏稱爲原始對象),所以這時候在 updateUser 函數中通過 user2 去修改原始對象,能更改是一個很正常的操作。

再分析第三個例子:
在這裏插入圖片描述

x 和 y 分別拷貝了 user1 和 user2 的地址值。發生交換:

在這裏插入圖片描述

數據沒有發生變化的原因很簡單,因爲這裏只更改了 x 和 y 的引用地址,跟 user1 和 user2 沒有任何關係。

最後再總結一下,最關鍵的是理解傳遞的是什麼,Java 傳遞的是值,如果是基本數據類型,這個值就是字面量的值,如果是引用數據類型,這個值就是地址。毋需糾結於“值傳遞”、“引用傳遞”這些概念。

歡迎關注公衆號
​​​​​​在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章