JAVA小菜鸟排坑系列

【排坑】java 值传递和引用传递

2017-12-21  本文已影响36人  汗菜

  最近在开发期间碰上一个关于引用的问题,加注释跟代码研究了好久才发现是对象引用的问题。下文举出了一些常见的传递引用的例子;

java 基本数据类型传递的是值,类、接口、数组传递的是引用

以下是一些传递引用的例子:

String str ="abc";
String str2 = str;  //abc
str = str2;    //true

str2 = str 是把str指向的内存地址传递给str2,str2存储的是指向 字符串常量池 的内存地址;Tips:字符串常量池中的字符串是不能改变的,内存的大小是不能改变的,有不同的字符串时,会新开辟一块内存保存字符串;

User user = new User();
user.setName("张学友");  //张学友
user.setAge(56);  //56

User user2 = user;  //{"name":"张学友","age":56}
user2.setAge(18);  //18

user.getAge(); //18
image.png

user2 = user 是把user指向的内存地址赋值给user2,user2和user同时指向相同的一块内存区域,操作user或user2修改其中的值,另一个的值引用的值也会改变,因为实质是同一块内存存储的值

User user = new User();
user.setName("张学友");  
user.setAge(56);  
            
User user2 = new User();
user2.setName("刘德华");  
user2.setAge(56);  
            
ArrayList<User> userList = new ArrayList<User>();
userList.add(user);
userList.add(user2);
ArrayList<User> userList2 = new ArrayList<User>(userList); //op1: 开辟一个新的内存地址 
System.out.println(userList == userList2); //false

userList2.add(new User());  // op2: 给userList2添加一个对象,userList不会变
System.out.println(userList.size());    //2
            
for (User u : userList2) {
    u.setAge(18);   //op3: 改变userList2中User对象年龄,user,user2,userList中的值都发生改变
}
System.out.println(user.getAge());  //18
System.out.println(userList.get(0).getAge());  //18

在做op1操作时,相当于对userList进行了拷贝,开辟了一个新的内存进行保存,即userList2,所以跟useList是不同的对象,所以我们在进行op2时,userList并不会增加一个User对象。
但是在做op3时,我们发现,user对象,user2对象,userList对象中的值都发生了改变,这说明,userList2中User对象其实是存的对user、user2实例的引用。在进行op1的时候,也只是将userList中的对象引用拷贝到了userList2中,对user实例其实是没有进行拷贝的;引用关系如下图:

image.png

那么问题来了,如何将两个list集合中的对象区分开呢?对userList进行 深拷贝

深拷贝和浅拷贝的区别在于,在拷贝对象时,是否对引用指向的对象进行拷贝,前者是后者否。
这里涉及到 深拷贝浅拷贝 的知识不在此多展开,有兴趣的同学可以在自己查阅资料了解。

这里推荐一种方式,利用fastJSON,进行两次转换后,获得相同值不同引用的新对象:

String jsonString = JSONObject.toJSONString(userList);
List<User> userList2 = JSONObject.parseArray(jsonString, User.class);
上一篇下一篇

猜你喜欢

热点阅读