在 Java 中,方法的调用,只有值传递。(不同于 C++)
也就是说参数无论是引用类型还是基本类型,传过去的都是变量的副本,形参的操作,不影响原始内容。
但是如果对引用类型对象成员变量的修改,是因为实参和形参指向了同一个堆对象,实参内容(引用地址)并未修改。
上文“方法的调用”可以推广到 for 循环遍历处理等。
代码说明一切
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
/**
* 印证 Java 只有值传递
* 方法传递的仅仅是引用的一个副本值
* @author duzhen.dz
* @since 2019-11-15
*/
public class TestChallenge {
public static void main(String args[]) throws InterruptedException {
User user1 = new User("user1");
User user2 = new User("user2");
System.out.println(System.identityHashCode(user1));
chalengeValue(user1);
System.out.println(user1);
System.out.println(System.identityHashCode(user1));
// 767010715
// User{name='user1'}
// 767010715
// 结论:形参的重新赋值未修改实参(地址)
System.out.println(System.identityHashCode(user2));
chalengeName(user2);
System.out.println(user2);
System.out.println(System.identityHashCode(user2));
// 110431793
// User{name='newUser'}
// 110431793
// 结论:形参的重新赋值未修改实参(地址),仅仅修改了实参地址对应的堆内对象的成员变量
int a = 1;
chalengeValue(a);
System.out.println("a : " + a);
// a : 1
// 结论:形参的重新赋值未修改实参值
List<User> users = Arrays.asList(new User("user1"), new User("user2"));
for (User user : users) {
chalengeValue(user);
}
System.out.println(JSON.toJSONString(users));
// [{"name":"user1"},{"name":"user2"}]
// 结论:推广至 for 循环遍历调用
}
public static void chalengeValue(User user) {
User newUser = new User("newUser");
user = newUser;
}
public static void chalengeValue(int v) {
v = 2;
}
public static void chalengeName(User user) {
user.setName("newUser");
}
static class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
}
参考文章
https://juejin.im/post/5bce68226fb9a05ce46a0476
https://blog.csdn.net/wuwenxiang91322/article/details/17038557
在Java中所有的参数传递,不管基本类型还是引用类型,都是值传递,或者说是副本传递。只是在传递过程中:
如果是对基本数据类型的数据进行操作,由于原始内容和副本都是存储实际值,并且是在不同的栈区,因此形参的操作,不影响原始内容。
如果是对引用类型的数据进行操作,分两种情况,一种是形参和实参保持指向同一个对象地址,则形参的操作,会影响实参指向的对象的内容。一种是形参被改动指向新的对象地址(如重新赋值引用),则形参的操作,不会影响实参指向的对象的内容。