方法中对象参数是按引用传递的,这是一种普遍的误解。
举个例子解释一下也让自己更深入理解这个问题
public class demo {
public static void main(String[] args) {
String sayHello1 = "你好";
String sayHello2 = "世界";
//传递引用类型的参数
hello(sayHello1,sayHello2);
//打印交换位置后的字符串②
System.out.printf("%s%3s",sayHello1,sayHello2);
}
public static void hello(String sayHello1,String sayHello2){
//打印传递的字符串
System.out.printf("%s%3s\n",sayHello1,sayHello2);
String temp;
//修改String变量的值,交换位置
temp = sayHello1;
sayHello1 = sayHello2;
sayHello2 = temp;
//打印交换位置后的字符串①
System.out.printf("%s%3s\n",sayHello1,sayHello2);
}
}
运行结果:
你好 世界
世界 你好
你好 世界
由结果可知,在方法的内部接收到的参数确实为传递过来的字符串引用。所以交换数据后,方法内部的输出语句成功打印了交换后的结果。但是回到main方法打印第二条输出语句的时候却发现并没有交换数据,如果按照引用传递的理解,这个地方应该已经被修改了才对,可是并没有。这究竟是为什么呢?
这个结果就说明:java语言对对象并不是采用引用传递,而是通过值传递的方式来实现引用传递。它实际上传递的是对象引用的副本,这个副本指向了这个对象的引用。所以当你在方法中修改它的值,实际上修改的是这个对象引用的副本,而不是对象引用本身。说的再直白一点,当对这个对象引用的副本进行修改的时候,会为其指向一个新的字符串的地址,但改变的只是副本的引用地址,并不会改变原来的变量指向的地址。
现在,再看一个代码示例
public class demo {
public static void main(String[] args) {
UserInfo userInfo = new UserInfo();
userInfo.setName("张三");
System.out.println(userInfo);
editUser(userInfo);
System.out.println(userInfo);
}
public static void editUser(UserInfo user){
user.setName("赵四");
user.setAge(40);
user.setSex((byte) 0);
}
}
class UserInfo{
private String name;
private int age;
private byte sex;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public byte getSex() {
return sex;
}
public void setSex(byte sex) {
this.sex = sex;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + ''' +
", age=" + age +
", sex=" + sex +
'}';
}
}
运行结果:
UserInfo{name=‘张三’, age=0, sex=0}
UserInfo{name=‘赵四’, age=40, sex=0}
为什么这次修改成功了呢?
因为虽然说传递的参数是对象引用的副本,但是副本与对象引用指向的是同一地址。当对相同引用内部的数据进行修改的时候,是没有问题的。而第一个示例中并不是对相同引用内部的数据进行修改,而是相当于直接修改了引用,所以结果才会不同。
再看一个示例就能明白是怎么一回事了,这次稍微修改一下editUser方法中代码
public static void main(String[] args) {
UserInfo userInfo = new UserInfo();
userInfo.setName("张三");
System.out.println(userInfo);
editUser(userInfo);
System.out.println(userInfo);
}
public static void editUser(UserInfo user){
user = new UserInfo();
user.setName("赵四");
user.setAge(40);
user.setSex((byte) 0);
}
运行结果:
UserInfo{name=‘张三’, age=0, sex=0}
UserInfo{name=‘张三’, age=0, sex=0}
当把editUser中的user指向一个新的实例,就会发现方法中的修改不会对传递过来的对象本身造成任何影响。现在就可以得到一个结论:方法不能让一个对象参数引用一个新的对象,但是可以改变对象参数的状态(对象中的变量)。
为什么说对象参数的传递实际上是值传递,因为传递给方法的对象参数实际上只是对象引用的副本,当方法执行结束后,这些副本就会被丢弃,对这些对象本身的修改并没有持久效果,所以说对象引用实际上是按值传递的。