打造不可变集合优化之对象拷贝
前序
在上一篇打造不可变集合的博客中说到,关于集合复制的优化。
Collections.copy(copyList,list);
上面的方法,是浅拷贝,会存在当引用层次比较深的时候,仍旧存才不可变集合中内容可变的情况,比如下面的代码:
实体类的初始化
Student student = new Student();
HashMap<String, Object> friendMap = new HashMap<>();
Person qwe = new Person(new Doctor("qwe"));
friendMap.put("qwe", qwe);
student.friendMap = friendMap;
不可变集合可变操作如下:
Doctor doctor = new Doctor("qwe");
Person person = new Person(doctor);
ArrayList<Person> persons = new ArrayList<>();
persons.add(person);
ArrayList<Object> copyList = new ArrayList<>(Arrays.asList(new Object[10]));
Collections.copy(copyList,persons);
doctor.name = "asd";
我们会发现,当doctor的内容更改时,copyList集合里面的内容也会更改,这样就达不到我们要求的不可变集合了。
我们需要深度拷贝
第一种,clone的方式。
此方式如果要达到深度拷贝的话,实体类需要实现Cloneable接口,并且重写clone方法。
有两个缺点:
1、耦合度太高,如果实体类引用类型的属性有变动,就需要修改clone的方法
2、如果引用层级比较深的话,要重写多个clone方法,工作量大。
所以我们不采用这用方法实现深度拷贝。
第二种,序列化的方式。
我们经常理解的便是java自带的序列化(完美的选择)
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(student);
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
Student copyStudent = (Student)objectInputStream.readObject();
这种方法对实体类的要求只有一点,就是要实现Serializable接口。
另外,也可以使用json字符串序列化的形式,深度复制对象。
但是存在一定的缺陷,比如下面的代码:
String stringStudent = JSON.toJSONString(student);
Student Jsonstudent = JSONObject.parseObject(stringStudent, Student.class);```
使用fastJson,其中引用层级:student–>list–>person–>doctor,
序列化为字符串的时候没有问题,
但是解析为对象的时候,doctor会解析成一个JsonObject(底层是一个Map)。这时当我们使用到doctor的时候就会报如下错误了:
这是fastJson的一个坑,请铭记。
java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to com.example.doman.Person