赞
踩
目录
3.2.1Apache Commons Lang【不建议使用】
fastjson:需要使用TypeReference指定泛型
探索HashMap的浅复制、浅拷贝(shallow copy)和深复制、深拷贝(deep copy),以及各自的几种实现方式,包括JDK里的和引用第三方的。
浅复制的HashMap,是一个新的HashMap,拥有和原HashMap相同的key,相同的value
比如,我们创建一个员工类Employee:
- public class Employee {
- private String name;
-
- private Address address;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public Address getAddress() {
- return address;
- }
-
- public void setAddress(Address address) {
- this.address = address;
- }
-
- }
一个Address类
-
- public class Address {
- private String name;
-
- private String province;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getProvince() {
- return province;
- }
-
- public void setProvince(String province) {
- this.province = province;
- }
- }
测试:
- import org.junit.Test;
-
- import java.util.HashMap;
-
- public class TestHashMapCopy {
- private HashMap<String , Employee> originalMap= new HashMap();
-
- @Test
- public void testShallowCopy() {
- Employee emp1 = new Employee();
- emp1.setName("刘亦菲");
- originalMap.put("emp1", emp1);
-
- Employee emp2 = new Employee();
- emp2.setName("范冰冰");
- originalMap.put("emp2",emp2);
-
- HashMap<String ,Employee> shallowCopy = new HashMap<>(originalMap);
- assert shallowCopy != orignalMap;
-
- // System.out.println("orignalMap beforeChange" + JacksonJsonUtil.obj2JsonString(orignalMap));
- // System.out.println("shallowCopy beforeChange" + JacksonJsonUtil.obj2JsonString(shallowCopy));
- emp1.setName("关晓彤");
- Employee shallowCopyEmp2 = shallowCopy.get("emp2");
- shallowCopyEmp2.setName("emp2改名字");
- // System.out.println("orignalMap afterChange" + JacksonJsonUtil.obj2JsonString(orignalMap));
- // System.out.println("shallowCopy afterChange" + JacksonJsonUtil.obj2JsonString(shallowCopy));
- // assert结果是true,表示浅复制map里的emp1和原map里的emp1是同一个对象,
- // 无论是在浅复制map里更改emp1的属性,还是在原map里更改emp1的属性,对方都会跟着更改
- assert (shallowCopy.get("emp1")).equals(orignalMap.get("emp1"));
- }
- }
测试结果:
浅复制,原map和复制map不是同一个对象,但是map里的value如果是引用类型的话,那么该引用类型是同一个对象,比如测试例子中的emp1.
更改了emp1里的属性之后,原map和浅复制map里的emp1属性都变了,会相互影响。
深复制的HashMap,是一个新的HashMap,并且深复制了所有的属性。它为所有的key、value、mappings创建了新的对象,
因此原map和深复制map更改了值之后,相互不影响。
深复制的实现,比如Apache Commons Lang,但是要求map的所有key和value是实现了Serializable接口。
HashMap(Map<? extends K,? extends V> m) :
HashMap<String ,Employee> shallowCopy = new HashMap<>(originalMap);
HashMap<String ,Employee> shallowCopy = (HashMap<String, Employee>) originalMap.clone();
- HashMap<String ,Employee> shallowCopy = new HashMap<String , Employee>();
- Set<Map.Entry<String, Employee>> entries = originalMap.entrySet();
- for(Map.Entry<String, Employee> entry: entries) {
- shallowCopy.put(entry.getKey(), entry.getValue());
- }
- HashMap<String ,Employee> shallowCopy = new HashMap<String , Employee>();
- shallowCopy.putAll(originalMap);
- HashMap<String, Employee> shallowCopy = (HashMap<String, Employee>) originalMap.entrySet().stream().collect(
- // 阿里开发手册里集合处理第3条有写toMap的规范:要使用带有BinaryOperator的方法
- // Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue
- Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (v1, v2) -> v2
- ));
Map<String, Employee> shallowCopy = ImmutableMap.copyOf(originalMap);
主要是序列化、反序列化方式
但是要求map的所有key和value都实现了Serializable接口,包括对象里的对象属性也需要
public class Employee implements Serializable {
public class Address implements Serializable {
HashMap<String, Employee> deepCopy = SerializationUtils.clone(originalMap);
常见的序列化工具,Jackson、Gson、fastjson等,但是要注意反序列化为Map的时候,需要指定对应的泛型
可以使用Jackson的工具类,封装下列的方法
- ObjectMapper objectMapper = new ObjectMapper();
- String originalJsonStr = objectMapper.writeValueAsString(originalMap);
- HashMap<String, Employee> deepCopy = new HashMap<>();
- deepCopy = objectMapper.readValue(originalJsonStr, new TypeReference<HashMap<String, Employee>>() {
- });
-
- ObjectMapper objectMapper = new ObjectMapper();
- String originalJsonStr = objectMapper.writeValueAsString(originalMap);
- JavaType javaType = objectMapper.getTypeFactory().constructParametricType(HashMap.class, String.class, Employee.class);
- HashMap<String, Employee> deepCopy = objectMapper.readValue(originalJsonStr, javaType);
- // Gson序列化,需要使用泛型参数TypeToken
- Gson gson = new Gson();
- String json = gson.toJson(originalMap);
- HashMap<String, Employee> deepCopy = new HashMap<>();
- // 注意,gson的jsonStr转集合,需要使用泛型参数TypeToken,才能准确获取到需要的对象
- deepCopy = gson.fromJson(json, new TypeToken<HashMap<String, Employee>>(){}.getType());
- // fastJson序列化,注意要使用TypeReference指定泛型
- String originalJsonStr = JSON.toJSONString(originalMap);
- HashMap<String, Employee> deepCopy = JSON.parseObject(originalJsonStr,new TypeReference<HashMap<String, Employee>>(){});
-
常用的序列化框架:
JDK Serializable、FST、Kryo、Protobuf、Thrift、Hession和Avro、Protostuff,3.7.2里提到的也是,只是是序列化成json结构
序列化框架的详情可以看下另一篇博客【待发布】
因为Protostuff常规上只支持序列化、反序列化Bean对象,不支持List、Map,因此这里建了一个包装类Wrapper:
注:List、Map,也可以使用MessageCollectionSchema,参考:How do I serialize list or map collection objects? · Issue #233 · protostuff/protostuff · GitHub
- public class SerializeWrapper {
-
- private Object obj = null;
-
- public Object getObj() {
- return obj;
- }
-
- public void setObj(Object obj) {
- this.obj = obj;
- }
- }
-
- Schema<SerializeWrapper> schema = RuntimeSchema.getSchema(SerializeWrapper.class);
- SerializeWrapper SerializeWrapper = new SerializeWrapper();
- SerializeWrapper.setObj(originalMap);
-
- LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
- final byte[] protostuff;
- try{
- protostuff = ProtostuffIOUtil.toByteArray(SerializeWrapper,schema,buffer);
- } finally {
- buffer.clear();
- }
- ProtostuffIOUtil.mergeFrom(protostuff, SerializeWrapper, schema);
- HashMap<String, Employee> deepCopy = (HashMap<String, Employee>) SerializeWrapper.getObj();
还有其它的框架可以实现,比如HuTool等
浅复制的话,上面的浅复制方法都可以选择;深复制的话,推荐使用Protostuff等序列化工具,最好不需要对象实现序列化接口,或者需要转换成json格式。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。