Java对象深拷贝 终极方案 deep clone an object
创始人
2024-01-19 19:08:22

Java对象深拷贝 终极方案

    • 定义 深拷贝
    • 深拷贝常见误区
      • `spring / apache commons ` 等工具类的 `BeanUtils.copy` 方法 ❌
    • 正确做法: 上中下3策 ✔
      • json 序列化 (用jackson,别用其他的gson/fastjson/json-lib 等,不解释)
        • objectMapper 工具类初始化
        • 1. 对象 <===> json字符串 互相转换 (下策)
        • 2. 对象 <===> jsonNode 互相转换 (中策)
        • 3. 对象 <===> TokenBuffer 互相转换 (上策)

定义 深拷贝

  • 必须是全新的对象,object堆内存地址是全新的;
  • 对象的各个属性值 prop Value,也是全新的,指向全新的堆内存地址。
  • 作用: 原有旧对象和新对象,可以独立修改各自的属性值,互相之间没影响。
  • 场景:
    • java的method 参数传递的是内存地址,也就是对象的引用句柄,只有 primitive 基本类型和String 作为参数时,传递的才是值
    • 某个对象,需要作为 多个方法的参数,进行不同的操作。
      为了防止这个原始对象的属性值被意外修改,就需要 深拷贝为新对象。
      操作新对象,不会对 原始对象有任何影响。
    • 该对象作为参数进行传递的次数越多,因为属性的内存地址都是一样的,属性值被修改的风险就越高

深拷贝常见误区

spring / apache commons 等工具类的 BeanUtils.copy 方法 ❌

  • 查看源码可知,使用的是 对象的get/set 方式实现的
  • 对象虽然是新的,但是 属性值的内存地址是相同的
  • 修改新对象的属性值,会同时影响原有对象的属性值
  • 如果属性是 特殊类型比如map 或者 list 或者 嵌套对象属性,可能就不好使了
    在这里插入图片描述

正确做法: 上中下3策 ✔

json 序列化 (用jackson,别用其他的gson/fastjson/json-lib 等,不解释)

类似 java 的对象序列化和反序列化过程( object Serialization & deserialization ),产生的是全新的对象
不同的是,java 对象序列化需要落地为磁盘文件,jackson 序列化则正常运行在jvm内存中。

Jackson 是个神奇的东东,共有3种方式可实现深拷贝,来源

objectMapper 工具类初始化

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.util.TokenBuffer;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import java.util.List;@Slf4j
@Component
public class JacksonUtils {@AutowiredObjectMapper objectMapper;private static JacksonUtils MAPPER;/*** 非 Controller 层使用 @Autowired 方式注入 spring 初始化好的全局单例  objectMapper* 无需自己手动 new ObjectMapper();*/@PostConstructpublic void init(){MAPPER = this; // JacksonUtils 类的单例 beanMAPPER.objectMapper = this.objectMapper; // spring启动过程中,会暴露该 objectMapper 单例}
}

1. 对象 <===> json字符串 互相转换 (下策)

2. 对象 <===> jsonNode 互相转换 (中策)

3. 对象 <===> TokenBuffer 互相转换 (上策)

/*** 不同class类型拷贝* @Param clazz 这个类,必须有1个默认的构造 方法,这是使用 Jackson 正反序列化必须的; * 如果是Gson 进行正反序列化,则没有该 构造方法 的要求 : * Gson 参考 https://www.baeldung.com/java-deep-copy#2-json-serialization-with-gson*/
@SneakyThrows
public static  T deepClone(Object javaObj, Class clazz) {ObjectMapper mapper = MAPPER.objectMapper;// method 1 : json string 🚗// return mapper.readValue(mapper.writeValueAsString(javaObj), clazz);// method 2 : jsonNode tree 🛫// return mapper.treeToValue(mapper.valueToTree(javaObj), clazz);// method 3 : token buffer 🚀TokenBuffer tb = new TokenBuffer(mapper, false);mapper.writeValue(tb, javaObj);return mapper.readValue(tb.asParser(), clazz);
}/*** 相同class类型拷贝*/
@SneakyThrows
public static  T deepClone(T source) {return (T) deepClone(source, source.getClass());
}

初始化工具类,来源todo
深拷贝代码参考来源

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
苁蓉的食用方法 鲜苁蓉的吃法有... 肉苁蓉号称“温而不热,补而不峻,暖而不燥,滑而不泄,故有从容之名。”历来也是传统药食同源的滋补佳品。...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
阳澄湖在哪里哪个省的 阳澄湖是... 点击题目下方苏州生活指南有用 有趣 有态度近期的阳澄湖度很高,3月24日,央视二套《第一时间》直播连...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...