是否有任何用于深度克隆java集合的实用程序:
数组
清单
地图
注意:在不使用序列化的情况下更喜欢某些解决方案,但使用Object.clone()方法.我可以肯定我的自定义对象将实现clone()方法,并将只使用可克隆的java标准类...
我认为以前的绿色答案很糟糕,为什么你会问?
它增加了很多代码
它要求您列出要复制的所有字段并执行此操作
当使用clone()时,这对于列表不起作用(这是HashMap的clone()所说的:返回此HashMap实例的浅表副本:键和值自身未被克隆.)所以你最终手动完成它(这使得我哭了)
哦顺便说一下序列化也很糟糕,你可能不得不在整个地方添加Serializable(这也让我哭).
那么解决方案是什么:
Java深度 克隆库克隆库是一个小型的开源(apache许可证)java库,它深入克隆对象.对象不必实现Cloneable接口.实际上,这个库可以克隆任何java对象.如果您不希望修改缓存对象或者只是想要创建对象的深层副本,则可以在缓存实现中使用它.
Cloner cloner=new Cloner(); XX clone = cloner.deepClone(someObjectOfTypeXX);
请访问https://github.com/kostaskougios/cloning查看
在Java中复制对象的所有方法都有严重的缺陷:
克隆
clone()方法受到保护,因此除非有问题的类使用公共方法覆盖它,否则无法直接调用它.
clone()不会调用构造函数.任何构造函数.它将分配内存,分配内部class
字段(您可以通过其读取getClass()
)并复制原始字段.
有关clone()的更多问题,请参阅Joshua Bloch的书" Effective Java,Second Edition "的第11项
连载
序列化更糟糕; 它有许多缺点,clone()
然后有一些缺陷.约书亚有一整章只有四个项目.
我的解决方案
我的解决方案是为我的项目添加一个新界面:
public interface Copyable{ T copy (); T createForCopy (); void copyTo (T dest); }
代码如下所示:
class Demo implements Copyable{ public Demo copy () { Demo copy = createForCopy (); copyTo (copy); return copy; } public Demo createForCopy () { return new Demo (); } public void copyTo (Demo dest) super.copyTo (dest); ...copy fields of Demo here... } }
不幸的是,我必须将此代码复制到我的所有对象,但它始终是相同的代码,因此我可以使用Eclipse编辑器模板.好处:
我可以决定调用哪个构造函数以及如何初始化哪个字段.
初始化以确定性顺序发生(根类到实例类)
我可以重用现有的对象并覆盖它们
输入安全
单身人士留着单身人士
对于标准Java类型(如集合等),我使用可以复制它们的实用程序类.这些方法有标记和回调,所以我可以控制副本的深度.
浅克隆的集合是很容易的,但如果你想深克隆,图书馆可能会做你比手更好的编码它(因为要克隆的元素里面集合为好).
就像这个答案一样,我使用了Cloner库,并专门针对XStream进行了性能测试(可以通过序列化然后反序列化来克隆')和二进制序列化.虽然XStream在向/从xml序列化方面非常快,但克隆在克隆方面要快得多:
0.0851 ms:xstream(通过序列化/反
序列化克隆)0.0223 ms:二进制序列化(通过序列化/反序列化克隆)
0.0017 ms:cloner
*克隆一个简单对象(两个字段)的平均时间,没有默认的公共构造函数.运行10,000次.
除了快速,这里有更多选择克隆人的理由:
执行任何对象的深度克隆(即使是那些你自己不写的对象)
每次添加字段时,都不必使clone()方法保持最新
您可以克隆没有默认公共构造函数的对象
适用于Spring
(优化)不克隆已知的不可变对象(如Integer,String等)
使用方便.例:
cloner.deepClone(anyObject);
我是克隆人提出的克隆人lib的创造者.这是一个克隆对象的解决方案,无需编写任何额外的代码(不需要可序列化的对象或impl clone()方法)
布拉德说,这是非常快的,最近我上传了一个更快的版本.请注意,手动实现clone()方法将比克隆lib更快,但是您需要再次编写大量代码.
Cloner lib对我来说效果很好,因为我在一个缓存实现中使用它来处理流量非常大的站点(每天约100万个请求).缓存应该每个请求克隆大约10个对象.它非常可靠和稳定.但请注意克隆并非没有风险.可以将lib配置为打印在dev期间克隆的每个类实例.通过这种方式,您可以检查它是否克隆了您认为应该克隆的内容 - 对象图可以非常深,并且可以包含对大量对象的引用.使用clone lib,您可以指示它不克隆您不需要的对象,即单例.
深度克隆任意集合的一种通用方法是将其序列化为流,然后将其读回新集合.除了是相同的副本之外,你将完全重新水化与旧的没有任何关系的新对象.
查看Bruno的答案,获取Apache Commons序列化实用程序类的链接,如果这是您决定采用的路线,这将非常有用.
一种可能性是使用序列化:
Apache Commons提供SerializationUtils