网站首页 > 精选教程 正文
浅拷贝是指在对一个对象进行拷贝时,只拷贝对象本身和其中的基本数据类型,而不拷贝对象内部的引用类型。因此,在浅拷贝的对象中,引用类型的变量指向的依旧是原始对象中的引用。
深拷贝是指在对一个对象进行拷贝时,不仅拷贝对象本身和其中的基本数据类型,同时也拷贝对象内部的引用类型。因此,在深拷贝的对象中,引用类型的变量指向的是全新的对象。
cloning
克隆库是一个小型的开源(Apache许可)Java库,用于深度克隆对象。对象不必实现可克隆接口。实际上,这个库可以克隆任何Java对象。如果您不想修改缓存对象,或者每当您想创建对象的深度副本时,它可以在缓存实现中使用。
重要提示:Java类的深度克隆可能意味着数千个对象被克隆!另外,克隆文件和流可能会导致JVM崩溃。强烈建议在开发期间启用将克隆类转储到stdout,以便查看克隆的内容。
<dependency>
<groupId>io.github.kostaskougios</groupId>
<artifactId>cloning</artifactId>
<version>1.10.3</version>
</dependency>
Github: https://github.com/kostaskougios/cloning
cloning 测试代码
cloning 可以深度克隆任何 java 对象, 简单对象,复杂对象和集合对象,集合中的每个元素也都会被深度克隆。简单易用,功能强大。
publicclass CloningExp {
public static void main(String[] args) {
Cloner cloner = new Cloner();
// clone 简单对象
Bean1 bean1 = new Bean1();
bean1.setF1("XA");
bean1.setF2(478354);
System.out.println("bean1 -> " + bean1);
Bean1 clonedBean1 = cloner.deepClone(bean1);
System.out.println("clonedBean1 -> " + clonedBean1);
System.out.println("bean1 == clonedBean1 -> " + (bean1 == clonedBean1));
// clone 复杂对象
Bean2 bean2 = new Bean2();
bean2.setF1("VVV");
bean2.setF2(bean1);
System.out.println("bean2 -> " + bean2);
Bean2 clonedBean2 = cloner.deepClone(bean2);
System.out.println("clonedBean2 -> " + clonedBean2);
System.out.println("bean2 == clonedBean2 -> " + (bean2 == clonedBean2));
System.out.println("bean2.bean1 == clonedBean2.bean1 -> " + (bean2.getF2() == clonedBean2.getF2()));
// clone 集合
List<Bean1> bean1List = new ArrayList<>();
bean1List.add(new Bean1("Bean1-1" , 1));
bean1List.add(new Bean1("Bean1-2" , 1));
bean1List.add(new Bean1("Bean1-3" , 1));
System.out.println("bean1List -> " + bean1List);
List<Bean1> clonedBean1List = cloner.deepClone(bean1List);
System.out.println("clonedBean1List -> " + clonedBean1List);
System.out.println("bean1List == clonedBean1List -> " + (bean1List == clonedBean1List));
Map<Bean1 , Bean2> map = new HashMap<>();
Bean1 mapBean1 = new Bean1("Bean1-1", 1);
Bean2 mapBean2 = new Bean2("Bean2-1", mapBean1);
map.put(mapBean1 , mapBean2);
System.out.println("map -> " + map);
Map<Bean1, Bean2> clonedMap = cloner.deepClone(map);
System.out.println("clonedMap -> " + clonedMap);
System.out.println("map == clonedMap -> " + (map == clonedMap));
Cloner clonedCloner = cloner.deepClone(cloner);
System.out.println("cloner == clonedCloner -> " + (cloner == clonedCloner));
Map<String , Object> sourceMap = new HashMap<>();
sourceMap.put("1" , new Bean1("CAC" , 555));
sourceMap.put("2" , new Bean1("AXC" , 5589));
sourceMap.put("3" , new Bean1("bbv" , 76));
sourceMap.put("4" , "dasfsdgsdg");
sourceMap.put("5" , new Object());
sourceMap.put("6" , new ArrayList<>());
sourceMap.put("7" , 99999999999L);
sourceMap.put("8" , new HashMap<>());
long startTimeMillis = System.currentTimeMillis();
for (int i = 0 ;i < 500000; i++) {
cloner.deepClone(sourceMap);
}
System.out.println("time cost -> " + (System.currentTimeMillis() - startTimeMillis) + " ms");
}
@Data
@AllArgsConstructor
@NoArgsConstructor
staticclass Bean1 {
private String f1;
private Integer f2;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
staticclass Bean2 {
private String f1;
private Bean1 f2;
}
}
bean1 -> CloningExp.Bean1(f1=XA, f2=478354)
clonedBean1 -> CloningExp.Bean1(f1=XA, f2=478354)
bean1 == clonedBean1 -> false
bean2 -> CloningExp.Bean2(f1=VVV, f2=CloningExp.Bean1(f1=XA, f2=478354))
clonedBean2 -> CloningExp.Bean2(f1=VVV, f2=CloningExp.Bean1(f1=XA, f2=478354))
bean2 == clonedBean2 -> false
bean2.bean1 == clonedBean2.bean1 -> false
bean1List -> [CloningExp.Bean1(f1=Bean1-1, f2=1), CloningExp.Bean1(f1=Bean1-2, f2=1), CloningExp.Bean1(f1=Bean1-3, f2=1)]
clonedBean1List -> [CloningExp.Bean1(f1=Bean1-1, f2=1), CloningExp.Bean1(f1=Bean1-2, f2=1), CloningExp.Bean1(f1=Bean1-3, f2=1)]
bean1List == clonedBean1List -> false
map -> {CloningExp.Bean1(f1=Bean1-1, f2=1)=CloningExp.Bean2(f1=Bean2-1, f2=CloningExp.Bean1(f1=Bean1-1, f2=1))}
clonedMap -> {CloningExp.Bean1(f1=Bean1-1, f2=1)=CloningExp.Bean2(f1=Bean2-1, f2=CloningExp.Bean1(f1=Bean1-1, f2=1))}
map == clonedMap -> false
cloner == clonedCloner -> false
time cost -> 447 ms
cloning 性能
Map<String , Object> sourceMap = new HashMap<>();
sourceMap.put("1" , new Bean1("CAC" , 555));
sourceMap.put("2" , new Bean1("AXC" , 5589));
sourceMap.put("3" , new Bean1("bbv" , 76));
sourceMap.put("4" , "dasfsdgsdg");
sourceMap.put("5" , new Object());
sourceMap.put("6" , new ArrayList<>());
sourceMap.put("7" , 99999999999L);
sourceMap.put("8" , new HashMap<>());
对 sourceMap 克隆 50万次耗时 447 ms
Apache Commons Lang3
Apache Commons Lang3 中有一个 SerializationUtils 类用来对目标对象进行深度克隆,它内部使用的是 JDK 内置的对对象的序列化和反序列化,所以使用 SerializationUtils 有个前提是对象必须实现了 Serializable 接口。
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.13.0</version>
</dependency>
SerializationUtils 测试代码
publicclass SerializationUtilsExp {
public static void main(String[] args) {
// clone 简单对象
Bean1 bean1 = new Bean1();
bean1.setF1("XA");
bean1.setF2(478354);
System.out.println("bean1 -> " + bean1);
Bean1 clonedBean1 = SerializationUtils.clone(bean1);
System.out.println("clonedBean1 -> " + clonedBean1);
System.out.println("bean1 == clonedBean1 -> " + (bean1 == clonedBean1));
// clone 复杂对象
Bean2 bean2 = new Bean2();
bean2.setF1("VVV");
bean2.setF2(bean1);
System.out.println("bean2 -> " + bean2);
Bean2 clonedBean2 = SerializationUtils.clone(bean2);
System.out.println("clonedBean2 -> " + clonedBean2);
System.out.println("bean2 == clonedBean2 -> " + (bean2 == clonedBean2));
System.out.println("bean2.bean1 == clonedBean2.bean1 -> " + (bean2.getF2() == clonedBean2.getF2()));
// clone 集合
ArrayList<Bean1> bean1List = new ArrayList<>();
bean1List.add(new Bean1("Bean1-1" , 1));
bean1List.add(new Bean1("Bean1-2" , 1));
bean1List.add(new Bean1("Bean1-3" , 1));
System.out.println("bean1List -> " + bean1List);
List<Bean1> clonedBean1List = SerializationUtils.clone(bean1List);
System.out.println("clonedBean1List -> " + clonedBean1List);
System.out.println("bean1List == clonedBean1List -> " + (bean1List == clonedBean1List));
HashMap<Bean1, Bean2> map = new HashMap<>();
Bean1 mapBean1 = new Bean1("Bean1-1", 1);
Bean2 mapBean2 = new Bean2("Bean2-1", mapBean1);
map.put(mapBean1 , mapBean2);
System.out.println("map -> " + map);
Map<Bean1, Bean2> clonedMap = SerializationUtils.clone(map);
System.out.println("clonedMap -> " + clonedMap);
System.out.println("map == clonedMap -> " + (map == clonedMap));
HashMap<String , Object> sourceMap = new HashMap<>();
sourceMap.put("1" , new Bean1("CAC" , 555));
sourceMap.put("2" , new Bean1("AXC" , 5589));
sourceMap.put("3" , new Bean1("bbv" , 76));
sourceMap.put("4" , "dasfsdgsdg");
sourceMap.put("5" , "AAAAAAAAAAAAAA");
sourceMap.put("6" , new ArrayList<>());
sourceMap.put("7" , 99999999999L);
sourceMap.put("8" , new HashMap<>());
long startTimeMillis = System.currentTimeMillis();
for (int i = 0 ;i < 500000; i++) {
SerializationUtils.clone(sourceMap);
}
System.out.println("time cost -> " + (System.currentTimeMillis() - startTimeMillis) + " ms");
}
@Data
@AllArgsConstructor
@NoArgsConstructor
staticclass Bean1 implements Serializable {
private String f1;
private Integer f2;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
staticclass Bean2 implements Serializable {
private String f1;
private Bean1 f2;
}
}
bean1 -> SerializationUtilsExp.Bean1(f1=XA, f2=478354)
clonedBean1 -> SerializationUtilsExp.Bean1(f1=XA, f2=478354)
bean1 == clonedBean1 -> false
bean2 -> SerializationUtilsExp.Bean2(f1=VVV, f2=SerializationUtilsExp.Bean1(f1=XA, f2=478354))
clonedBean2 -> SerializationUtilsExp.Bean2(f1=VVV, f2=SerializationUtilsExp.Bean1(f1=XA, f2=478354))
bean2 == clonedBean2 -> false
bean2.bean1 == clonedBean2.bean1 -> false
bean1List -> [SerializationUtilsExp.Bean1(f1=Bean1-1, f2=1), SerializationUtilsExp.Bean1(f1=Bean1-2, f2=1), SerializationUtilsExp.Bean1(f1=Bean1-3, f2=1)]
clonedBean1List -> [SerializationUtilsExp.Bean1(f1=Bean1-1, f2=1), SerializationUtilsExp.Bean1(f1=Bean1-2, f2=1), SerializationUtilsExp.Bean1(f1=Bean1-3, f2=1)]
bean1List == clonedBean1List -> false
map -> {SerializationUtilsExp.Bean1(f1=Bean1-1, f2=1)=SerializationUtilsExp.Bean2(f1=Bean2-1, f2=SerializationUtilsExp.Bean1(f1=Bean1-1, f2=1))}
clonedMap -> {SerializationUtilsExp.Bean1(f1=Bean1-1, f2=1)=SerializationUtilsExp.Bean2(f1=Bean2-1, f2=SerializationUtilsExp.Bean1(f1=Bean1-1, f2=1))}
map == clonedMap -> false
time cost -> 26061 ms
SerializationUtils 性能
HashMap<String , Object> sourceMap = new HashMap<>();
sourceMap.put("1" , new Bean1("CAC" , 555));
sourceMap.put("2" , new Bean1("AXC" , 5589));
sourceMap.put("3" , new Bean1("bbv" , 76));
sourceMap.put("4" , "dasfsdgsdg");
sourceMap.put("5" , "AAAAAAAAAAAAAA");
sourceMap.put("6" , new ArrayList<>());
sourceMap.put("7" , 99999999999L);
sourceMap.put("8" , new HashMap<>());
对 sourceMap 克隆 50万次耗时 25716 ms
其他一些深拷贝的方式
- new 对象 (太累了且不优雅)
- JSON 序列化
- 使用一些对象序列化库,例如:Protocol Buffers , Kryo , ProtoStuff , Hessian ;
- 上一篇: 面试官问:什么是浅拷贝和深拷贝?
- 下一篇: 深拷贝和浅拷贝之list、dataframe
猜你喜欢
- 2025-01-08 JVM(Java虚拟机)从0到1全部合集,强烈建议收藏
- 2025-01-08 你见过哪些实用到爆的 Java 代码技巧?
- 2025-01-08 2019最全的Java架构师面试120题解析(MySQL/Redis/架构/高并发等)
- 2025-01-08 Python元组与字典用法详解
- 2025-01-08 金蝶一面:Java基本数据类型有哪些?包装类型的常量池技术了解么
- 2025-01-08 阿里云Java实习岗面试记录整理(附答案详解)
- 2025-01-08 Java基础八股文背诵版
- 2025-01-08 Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
- 2025-01-08 全网首发!马士兵内部共享—1658页《Java面试突击核心讲》
- 2025-01-08 百度文库不用会员也可复制文字
你 发表评论:
欢迎- 最近发表
-
- 我的世界光影MOD下载(我的世界光影mod下载安装)
- 我的世界1.7/1.8VoxelMap小地图MOD下载
- 我的世界1.7.10多世界 整合包(我的世界1.7.10forge整合包)
- 我的世界1.8最好用的修改器下载(我的世界1.8最好用的修改器下载安装)
- 我的世界更多弯曲动作MOD下载(我的世界更多弯曲动作mod下载手机版)
- 我的世界龙珠MOD下载(我的世界龙珠模组整合包下载)
- 我的世界1.7.10以太2 下载(我的世界以太2mod1.12.2)
- 我的世界虚拟人生MOD下载分享(我的世界虚拟人生下载安装)
- 我的世界无正版账号的简单联机方法(非网易版,仅适用于局域网)
- “我的语言极限,即是我的世界的极限。” ——《On Java》书籍推荐
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)