没有繁琐的各种内存指向图片,而是从概念中进行解释
值传递场景
值传递包含String类型以及基本数据类型,仅仅传递值,
基本上只会有一种场景
@Testpublic void testModify(){String str1 = "1";String str2 = this.modifyStr(str1);System.out.println("str1===>"+str1); // str1===>1System.out.println("str2===>"+str2); // str2===>2}private String modifyStr(String str){ // 形参strstr = "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
@Testpublic void testModify(){User user1 = new User();user1.setId("1");System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111this.modifyUser1(user1); System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>2}private User modifyUser1(User user){ // 形参useruser.setId("2"); // 引用了实参user1的地址,修改了实参user1的属性,所以user1也改了System.out.println("user-->HashCode:"+user.hashCode()); // user1-->HashCode:111return user;}
此时 modifyUser1() 方法里接收到的是user1的引用,因此改变形参user的值就等于改变user1的值。modifyUser1() 方法内user的hashCode和user1的hashCode一样,因此地址一样
场景2
@Testpublic void testModify(){User user1 = new User();user1.setId("1");System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111this.modifyUser2(user1); System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>1}private User modifyUser2(User user){ // 形参useruser = new User(); // 如果没有这行new User,则和场景1一样引用实参user1的地址// 但是new User()了,地址指向发生了改变,因此此时user为一个新的对象user.setId("2"); System.out.println("user-->HashCode:"+user.hashCode()); // user1-->HashCode:222return user;}
此时 modifyUser2() 方法里一开始接收到的是user1的引用,但是后面new User()了,创建了个新的对象,引用改变了(user1的hashCode不等于user的hashCode了),指向的是new User,之后形参user的修改基于的都是对new User()的修改了
场景3
当引入返回值时,重新看看modifyUser1的方法
@Testpublic void testModify(){User user1 = new User();user1.setId("1");System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111User user2 = this.modifyUser1(user1); System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>2user2.setId("3");System.out.println("user2.getId()===>"+user2.getId()); // user2.getId()===>3System.out.println("user1.getId()===>"+user1.getId()); // user1.getId()===>3}private User modifyUser1(User user){ // 形参useruser.setId("2"); // 引用了实参user1的地址,修改了实参user1的属性,所以user1也改了System.out.println("user-->HashCode:"+user.hashCode()); // user1-->HashCode:111return user;}
最后会发现user1和user2的id都为3,当把返回值赋给user2时,实际上返回的是引用,相当于user2 与user1的地址是一样的,所以此时修改user2的值,user1的值也会发生改变,实际上等价于以下代码
@Testpublic void testModify(){User user1 = new User();user1.setId("1");User user2 = user1; // 将user1的引用赋给user2,// 此时修改user1等于改user2,修改user2等于改user1user2.setId("3");System.out.println(user1.getId()); // 3System.out.println(user2.getId()); // 3}
场景4
当引入返回值时,重新看看modifyUser2的方法
@Testpublic void testModify(){User user1 = new User();user1.setId("1");System.out.println("user1-->HashCode:"+user1.hashCode()); // user1-->HashCode:111User user2 = this.modifyUser2(user1);System.out.println("user2-->HashCode:"+user2.hashCode()); // user2-->HashCode:222System.out.println("user1.getId():"+user1.getId()); // user1.getId():1System.out.println("user2.getId():"+user1.getId()); // user2.getId():2}private User modifyUser2(User user){ // 形参useruser = new User(); // 如果没有这行new User,则和场景1一样引用实参user1的地址// 但是new User()了,地址指向发生了改变,因此此时user为一个新的对象user.setId("2");System.out.println("user-->HashCode:"+user.hashCode()); // user-->HashCode:222return user; // 将引用返回}
最后会发现user1的id仍然是1,user2的id则为2,这是因为在modifyUser2方法里new User()了,而这个new出来的user对象最后引用赋给了user2(两者hashCode都是一样的,都为222),而user1的hashCode仍为111,此时user1和user2地址不一样,任意修改user1也不会影响user2,实际上等价于以下代码
@Testpublic 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()); // 1System.out.println(user2.getId()); // 2}