java值传递与引用传递
没有繁琐的各种内存指向图片,而是从概念中进行解释
值传递场景
值传递包含String类型以及基本数据类型,仅仅传递值,
基本上只会有一种场景
@Test
public void testModify(){
String str1 = "1";
String str2 = this.modifyStr(str1);
System.out.println("str1===>"+str1); // str1===>1
System.out.println("str2===>"+str2); // str2===>2
}
private String modifyStr(String str){ // 形参str
str = "2"; // 不管在这里进行什么操作,什么交换之类的,都不会改变实参(str1)
return str;
}
此时吧值赋给str2了,str1的值没有变化,吧String类型换成其他的int类型等基本数据类型,都是有效的
引用传递场景
引用传递基本上会包含4种场景,其中最后2种主要探讨的是返回值,网络资料中较少提到
假设一个User类,仅有一个属性id,注入Getter,Setter方法
// 使用lombok自动写入getter,setter方法
@Data
public class User{
private String id;
}
场景1
@Test
public void testModify(){
User user1 = new User();
user1.setId("1");
System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111
this.modifyUser1(user1);
System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>2
}
private User modifyUser1(User user){ // 形参user
user.setId("2"); // 引用了实参user1的地址,修改了实参user1的属性,所以user1也改了
System.out.println("user-->HashCode:"+user.hashCode()); // user1-->HashCode:111
return user;
}
此时 modifyUser1() 方法里接收到的是user1的引用,因此改变形参user的值就等于改变user1的值。modifyUser1() 方法内user的hashCode和user1的hashCode一样,因此地址一样
场景2
@Test
public void testModify(){
User user1 = new User();
user1.setId("1");
System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111
this.modifyUser2(user1);
System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>1
}
private User modifyUser2(User user){ // 形参user
user = new User(); // 如果没有这行new User,则和场景1一样引用实参user1的地址
// 但是new User()了,地址指向发生了改变,因此此时user为一个新的对象
user.setId("2");
System.out.println("user-->HashCode:"+user.hashCode()); // user1-->HashCode:222
return user;
}
此时 modifyUser2() 方法里一开始接收到的是user1的引用,但是后面new User()了,创建了个新的对象,引用改变了(user1的hashCode不等于user的hashCode了),指向的是new User,之后形参user的修改基于的都是对new User()的修改了
场景3
当引入返回值时,重新看看modifyUser1的方法
@Test
public void testModify(){
User user1 = new User();
user1.setId("1");
System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111
User user2 = this.modifyUser1(user1);
System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>2
user2.setId("3");
System.out.println("user2.getId()===>"+user2.getId()); // user2.getId()===>3
System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>3
}
private User modifyUser1(User user){ // 形参user
user.setId("2"); // 引用了实参user1的地址,修改了实参user1的属性,所以user1也改了
System.out.println("user-->HashCode:"+user.hashCode()); // user1-->HashCode:111
return user;
}
最后会发现user1和user2的id都为3,当把返回值赋给user2时,实际上返回的是引用,相当于user2 与user1的地址是一样的,所以此时修改user2的值,user1的值也会发生改变,实际上等价于以下代码
@Test
public void testModify(){
User user1 = new User();
user1.setId("1");
User user2 = user1; // 将user1的引用赋给user2,
// 此时修改user1等于改user2,修改user2等于改user1
user2.setId("3");
System.out.println(user1.getId()); // 3
System.out.println(user2.getId()); // 3
}
场景4
当引入返回值时,重新看看modifyUser2的方法
@Test
public void testModify(){
User user1 = new User();
user1.setId("1");
System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111
User user2 = this.modifyUser2(user1);
System.out.println("user2-->HashCode:"+user2.hashCode()); // user2-->HashCode:222
System.out.println("user1.getId():"+user1.getId()); // user1.getId():1
System.out.println("user2.getId():"+user1.getId()); // user2.getId():2
}
private User modifyUser2(User user){ // 形参user
user = new User(); // 如果没有这行new User,则和场景1一样引用实参user1的地址
// 但是new User()了,地址指向发生了改变,因此此时user为一个新的对象
user.setId("2");
System.out.println("user-->HashCode:"+user.hashCode()); // user-->HashCode:222
return user; // 将引用返回
}
最后会发现user1的id仍然是1,user2的id则为2,这是因为在modifyUser2方法里new User()了,而这个new出来的user对象最后引用赋给了user2(两者hashCode都是一样的,都为222),而user1的hashCode仍为111,此时user1和user2地址不一样,任意修改user1也不会影响user2,实际上等价于以下代码
@Test
public void testModify(){
User user1 = new User();
user1.setId("1");
User user2 = new User(); // 等价于在modifyUser2方法里new出来的对象
user2.setId("2");
// 此时user1和user2的引用就完全不一样了,修改互不影响
System.out.println(user1.getId()); // 1
System.out.println(user2.getId()); // 2
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!