相关文章:
本文目标:去掉高大上的专有名词,用最简单的方式解释“我这个 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 传递的是值,如果是基本数据类型,这个值就是字面量的值,如果是引用数据类型,这个值就是地址。毋需纠结于“值传递”、“引用传递”这些概念。
欢迎关注公众号