来聊聊Java为什么只有值传递
# 写在文章开头
关于参数传递一直有值传递、引用传递、指针传递三个概念,而Java使用的则是最经典的值传递,所以本文将针对java的值传递问题进行深入探讨分析,希望对你有帮助。
Hi,我是 sharkChili ,是个不断在硬核技术上作死的技术人,是 CSDN的博客专家 ,也是开源项目 Java Guide 的维护者之一,熟悉 Java 也会一点 Go ,偶尔也会在 C源码 边缘徘徊。写过很多有意思的技术博客,也还在研究并输出技术的路上,希望我的文章对你有帮助,非常欢迎你关注我的公众号: 写代码的SharkChili 。
同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 深入剖析与印证java值传递
# 什么是形参,什么是实参
形参即每个函数或者方法上的声明的占位符变量,如下代码整型的value就是一个形参:
public static int func(int value) {
return value << 1;
}
2
3
实参:调用函数或方法时传的参数,如下代码就的func内部传入的1就是实参:
public static void main(String[] args) {
System.out.println(func(1));
}
2
3
# 什么是值传递
值传递的概念也很简单,即形参会将传入的实参的值拷贝一份作为自己调用的样本,无论怎么改变都不会影响到实参的值:

# 什么是引用传递
这个概念在c++、c#中才有,简单来说就是将实参所指向的变量的引用地址传给形参,这样形参操作的就是实参所指向的变量的值,一旦形参改变那个值,实参看到的值也是有变化的:

# java常见的值传递两种示例
# 基本类型的值传递
可以看到下面代码将实参将值赋给形参后,形参无论如何交换对实参都没有任何作用:
public static void main(String[] args) {
int num1 = 10;
int num2 = 20;
swap(num1, num2);
//输出结果num1和num2值不变
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println("a = " + a);
System.out.println("b = " + b);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
对应的原因其实也很简单,调用swap时形参a和b会原原本本复制一份num1和num2的值,这也就意味着a、b在函数内的操作仅仅是针对它们自身并不会影响到num1和num2:

# java引用类型值传递
如下代码所示,将引用类型传给形参后发现实参的值被改变了,很多认为这明明就是引用类型传递。
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
System.out.println("before: " + arr[0]);
if (updateFirstElement(arr)) {
System.out.println("after: " + arr[0]);
}
}
public static boolean updateFirstElement(int[] array) {
if (array == null || array.length == 0) {
return false;
}
// 将数组的第一个元素变为0
array[0] = 0;
return true;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
输出结果
before: 1
after: 0
2
3
但是事与愿违,这里必须清楚一个java引用类型的值传递的机制,对于基本类型直接拷贝值.而对于引用类型,拷贝的是引用变量存储的地址,听到这里是不是觉得很混乱?没关系我们在写一段代码示例就知道了。
我们再来看一个例子,可以看到person这种引用类型作为实参传入后,对象xiaozhang和xiaoli的名字没有被交换,这就说明了java对引用类型做的也是值传递,传递的引用类型的地址值。我们不妨以一张图来说明
@Data
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public static void main(String[] args) {
Person xiaoZhang = new Person("小张");
Person xiaoLi = new Person("小李");
swap(xiaoZhang, xiaoLi);
//xiaozhang还是叫小张,xiaoLi还是叫小李
System.out.println("xiaoZhang:" + xiaoZhang.getName());
System.out.println("xiaoLi:" + xiaoLi.getName());
}
public static void swap(Person person1, Person person2) {
Person temp = person1;
person1 = person2;
person2 = temp;
System.out.println("person1:" + person1.getName());
System.out.println("person2:" + person2.getName());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
输出结果:
person1:小李
person2:小张
xiaoZhang:小张
xiaoLi:小李
2
3
4
如下图,可以看到形参的两个person复制到实参地址后,再进行交换操作,交换的不过是两个形参指向的地址而已,并没有改变实参的指向,所以这也就为什么我们说java就是一门值传递的语言:

# 小结
回到问题:Java是值传递还是引用传递?
答案:java是值传递,在进行方法传值操作时,本质上就是通过值复制的方式将引用地址信息进行传递,这就是为什么上文传入实参并修改实参指向的对象之后,原有的引用所指向的对象信息不变的原因。
我是 sharkchili ,CSDN Java 领域博客专家,mini-redis的作者,我想写一些有意思的东西,希望对你有帮助,如果你想实时收到我写的硬核的文章也欢迎你关注我的公众号: 写代码的SharkChili 。
同时也非常欢迎你star我的开源项目mini-redis:https://github.com/shark-ctrl/mini-redis (opens new window)
因为近期收到很多读者的私信,所以也专门创建了一个交流群,感兴趣的读者可以通过上方的公众号获取笔者的联系方式完成好友添加,点击备注 “加群” 即可和笔者和笔者的朋友们进行深入交流。

# 参考文献
为什么 Java 中只有值传递?:https://javaguide.cn/java/basis/why-there-only-value-passing-in-java/#案例2-传递引用类型参数1 (opens new window)
JavaSE-面向对象思想、原理以及内存图解:https://blog.csdn.net/shark_chili3007/article/details/107084097 (opens new window)