关于java的值传递与引用传递的问题,我们先来看一下百度百科的定义:
值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
根据定义来看,值传递与引用传递的区别就是,在函数中修改形参,是否会影响到实参。
接下来先看一个例子:
public static void main(String[] args) {
String a = "before";
System.out.println(a);
change(a);
System.out.println(a);
}
public static void change(String a) {
a = "after";
}
运行的结果是:
before change: before
after change: before
可以看出来,在change方法中修改形参并没有影响到实参。
我们再来看另一种例子:
public static void main(String[] args) {
User user = new User();
user.setId(0);
System.out.println("before change: " + user.getId());
changeUser(user);
System.out.println("after change: " + user.getId());
}
public static void changeUser(User user) {
user.setId(1);
}
运行的结果是:
before change: 0
after change: 1
这样子看起来,在changUser方法中修改形参的值影响到了实参,这又是怎么回事呢?
我们先来分析下第一种情况:
如上图所示,我们在change方法中修改了形参所指向的地址,指向After,实参依然指向Before。
我们再来分析下第二种情况:
如上图所示,我们在change方法中修改了user中id的值,形参所指向的地址没有变化,修改的是这个地址中的内容。所以实参指向的user的id发生了变化,所以Java是值传递,形参的修改并不会影响实参。
我们再来看看Java值传递会引起的问题,举个例子:
public static void main(String[] args) {
List<User> userList = new ArrayList<>();
User user = new User();
for(int i = 0; i < 10; i ++) {
user.setId(i);
userList.add(user);
}
System.out.println();
for(User u: userList) {
System.out.print(u.getId() + ",");
}
}
运行的结果是:
9,9,9,9,9,9,9,9,9,9,
为什么输出的都是9呢?我们命名是从0到9设置user的id,应该输出0到9才对。我们用一个图来说明。
userList中存的是user的地址,其实我们添加进去的都指向同一个地址,所以输出上边的结果。
所以我们在实际运用中要注意,add之前要先重新new一下,这样add进去的就是新的地址。不仅List,Map等也是一样的道理,要留意Java值传递引起的问题。