在解决这个问题之前,首先简单了解一下关于参数传递的相关概念:
形式参数是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”。
public static void main(String[] args) { ParamTest pt = new ParamTest(); pt.sout("Hollis"); //此处的"Hollis"为实际参数 } public void sout(String name) { //此处的name为形式参数 System.out.println(name); }
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
值传递 | 引用传递 | |
---|---|---|
根本区别 | 会创建实际参数的副本(copy) | 传入引用,不会进行参数的复制 |
所以 | 函数中无法改变原始对象(值) | 函数中可以改变原始对象(值) |
public class Main { public static void main(String[] args) { int a = 1; int b = 2; pass(a, b); System.out.println("a = " + a + " --- b = " + b); } private static void pass(int A, int B) { A = 10; B = 20; System.out.println("a = " + A + " --- b = " + B); } }
输出:
a = 10 --- b = 20 a = 1 --- b = 2
step1:
首先初始化了两个变量a,b;其中a指向1,b指向2;
然后将a,b传入pass方法中,这时候a,b分别创建出自己的副本传入方法中,形成了A指向1,B指向2的局面
step2:
在pass方法中,对复制出来的A,B变量进行重新赋值,使得A指向10,B指向20
结果:
public class Main { public static void main(String[] args) { String s1 = "hello"; pass(s1); System.out.println(s1); } private static void pass(String s2) { s2 = "world"; System.out.println(s2); } }
输出:
world hello
step1:
s2 = new String("world")
结果:
从结果中可以看出对于字符串类型的对象进行传递的时候,依然是复制了原始的s1,所以仍然是值传递。
public class Main { public static void main(String[] args) { User user = new User(); user.setAge(20); user.setName("小明"); System.out.println("print in pass , user is " + user); pass(user); System.out.println("print in pass , user is " + user); } private static void pass(User user) { user.setAge(21); user.setName("小花"); System.out.println("print in pass , user is " + user); } }
输出:
print in pass , user is User{name='小明', age=20} print in pass , user is User{name='小花', age=21} print in pass , user is User{name='小花', age=21}
step1:
然后将user作为参数传入pass方法,这事会创建一个user引用的复制品user(副),还是指向User对象
step2:
此时修改了user(副)对象想的成员属性,因为user和user(副)指向的User实体是完全一样的,因此修改了一个,另外一个也会跟着发生改变。
结果:
public class Main { public static void main(String[] args) { User user = new User(); user.setAge(20); user.setName("小明"); System.out.println("print in pass , user is " + user); pass(user); System.out.println("print in pass , user is " + user); } private static void pass(User user) { user = new User(); user.setAge(21); user.setName("小花"); System.out.println("print in pass , user is " + user); } }
输出:
print in pass , user is User{name='小明', age=20} print in pass , user is User{name='小花', age=21} print in pass , user is User{name='小明', age=20}
step1:
step2:
进入pass方法后,将user(副)指向了新的user对象,这是肯定不会对原来的对象产生影响
结果:
为了对比Java值传递的过程,我们来看一下如果Java采用了引用传递会出现什么情况?
step1: 同上
step2:
这里如果是引用传递,就不可能会进行值的复制,直接将user交给方法pass执行即可,所以就有了下面的情况
结果:
user = new User();
方法,也会对原来的user造成修改。