本文最后更新于:2023年7月9日 晚上
Java 基础的重要知识
Java 的变量是值传递还是引用传递?
我记得在最开始学习 Java 的时候,关于变量传参的方式是这样定义的:
对于基本数据类型 (int, double, long, float) Java 是值传递,而对于引用数据类型 (Array, String, List) Java 是引用传递,也就是直接传递变量地址。
值传递的例子
不过,最近看了一篇文章发现事实并非如此。先说结论:在 Java 中,所有变量都是值传递,无论是基本类型还是引用类型都是如此。 那么现在问题来了,既然 Java 中引用类型也是值传递,为什么方法内的操作变量会影响到外部的变量呢?看下方这段代码:
1 2 3 4 5 6 7 8 9 10 11 12
| public static void main(String[] args) { int[] arr = { 1, 2, 3, 4, 5 }; System.out.println("before change arr[0] = "+ arr[0]); change(arr); System.out.println("after change arr[0] = "+ arr[0]); }
public static void change(int[] array) { array[0] = 0; }
|
输出结果:
1 2
| before change arr[0] = 1 after change arr[0] = 0
|
可以看到,我们在 change
方法中对 array
进行修改后,函数外也看到了效果。为什么值传递呈现了引用传递的效果呢?关键点在于,Java 中传递的是变量地址值的副本。引用类型的参数在传递时,会将引用的地址值,复制一份传递到方法内部。前面 change
函数接收的实际上是 arr
地址的副本。在 change
方法内部,arr
和 array
两个变量都指向了同一个地址。所以,方法 change
对数组的修改会同步到方法外部。
引用传递的例子
我们再看一个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Person { private String name; }
public static void main(String[] args) { Person xiaoZhang = new Person("小张1"); Person xiaoLi = new Person("小李2"); swap(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());
person1.setName("person1 xl "); }
|
最终输出结果:
1 2 3 4
| person1:xiaoLi = 小李2 person2:xiaoZhang = 小张1 xiaoZhang:xiaoZhang = 小张1 xiaoLi:person1 xl
|
这个例子中,xiaoZhang = 小张1,xiaoLi = 小李2,我们在 swap 函数中交换了它们两个然后并打印。从输出结果中可以看出,在函数体内,它们两个确实是已经交换。但在函数体外部再打印,它们的值却没有任何变化。这也就印证了, Java 中引用变量传递的是地址的副本,而不是地址本身这个理论了。
我们在方法中交换两个变量,也只是交换的两个副本变量指向的地址,函数外部变量指向的地址的没有任何影响。
这种方式的好处在于,方法内部的操作不会莫名其妙地对外部造成影响,减少意想不到的结果。
总结
- Java 中,变量的传递都是值传递,不存在引用传递。
- 对于引用变量,在传递时,是先复制的引用变量的地址,然后再传递。