相關文章:
本文目標:去掉高大上的專有名詞,用最簡單的方式解釋“我這個 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 傳遞的是值,如果是基本數據類型,這個值就是字面量的值,如果是引用數據類型,這個值就是地址。毋需糾結於“值傳遞”、“引用傳遞”這些概念。
歡迎關注公衆號