关于Java:深度克隆实用程序推荐

您所在的位置:网站首页 java深度克隆对象 关于Java:深度克隆实用程序推荐

关于Java:深度克隆实用程序推荐

2023-03-13 20:00| 来源: 网络整理| 查看: 265

是否有用于深度克隆Java集合的实用程序:

数组 清单 地图

注意:更喜欢一些不使用序列化但使用Object.clone()方法的解决方案。 我可以确定我的自定义对象将实现clone()方法,并且仅使用可克隆的Java标准类...

相关讨论 如何在Java中对对象进行深拷贝? 使用克隆库为我节省了一天! github.com/kostaskougios/cloning

我认为以前的绿色答案不好,为什么您会问?

它添加了很多代码 它要求您列出所有要复制的字段并执行此操作 使用clone()时,这不适用于列表 (这是HashMap的clone()所说的:返回此HashMap实例的浅表副本:键和值本身未被克隆。)因此您最终不得不手动进行操作(这让我哭了)

哦,顺便说一句,序列化也很糟糕,您可能必须在各处添加Serializable(这也让我哭了)。

那么解决方案是什么:

Java深度克隆库 克隆库是一个小型的,开放源代码(Apache许可证)的Java库,用于深度克隆对象。对象不必实现Cloneable接口。实际上,该库可以克隆任何java对象。如果您不希望修改缓存的对象,或者想要创建对象的深层副本,则可以在缓存实现中使用它。

12Cloner cloner=new Cloner(); XX clone = cloner.deepClone(someObjectOfTypeXX);

在https://github.com/kostaskougios/cloning中查看

相关讨论 Cloner是一个很棒的库(只是它的性能有时会让我哭泣...但是我想您不能用反射做得更好) 此解决方案看起来更好。 Havent尝试了一下,但是此线程中有一些对克隆器非常肯定的注释。 在Android上无法使用... 先前的绿色答案是什么? @DaveFar stackoverflow.com/a/666231/570584 这个库有一个大问题。如果像这样使用deppClone(),则会发生太多复制!!!我的意思是,如果您有一个"枚举"在其主体中声明了"抽象"方法,并在从该枚举中克隆了一个字段后,强制每个常量为该抽象方法提供了不同的实现," =="不再适用于那些常量!这很容易引起问题...库中有一些解决方案。 registerFastCloner()和registerImmutable()都可以作为解决方案,还没有尝试过...而且我不知道它是否可以完全解决! 看一下:package mx.tests;导入com.rits.cloning.Cloner;公共类ClonerTest {枚举MyEnum {A {int getNumber(){返回11; }},B {int getNumber(){返回22; };抽象int getNumber(); }静态类Test {MyEnum m;公共Test(){m = MyEnum.A; }} public static void main(final String [] args){Test t1 = new Test();测试t2 = new Test();克隆c =新的Cloner(); t2 = c.deepClone(t2); System.out.println(t1.m == t2.m); }} 该库与Java 10不兼容-您知道任何替代方法吗?

用Java复制对象的所有方法都有严重的缺陷:

克隆

clone()方法是受保护的,因此除非所涉及的类使用公共方法覆盖它,否则您不能直接调用它。 clone()不调用构造函数。任何构造函数。它将分配内存,分配内部class字段(您可以通过getClass()读取)并复制原始字段。

有关clone()的更多问题,请参见Joshua Bloch的书" Effective Java,第二版"的第11条。

连载

序列化甚至更糟;它具有clone()的许多缺陷,然后是一些缺陷。约书亚(Joshua)整整一章都包含四个主题。

我的解决方案

我的解决方案是为项目添加新界面:

12345public interface Copyable {     T copy ();     T createForCopy ();     void copyTo (T dest); }

代码如下:

1234567891011121314class 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类型(例如集合等),我使用可以复制它们的实用程序类。这些方法具有标志和回调,因此我可以控制副本的深度。

相关讨论 通过在所有需要克隆的类中实现clone(),我做了类似的事情。最大的问题是,如果我有收藏,则必须对其进行迭代并自行复制... 使用一个接受Collection并返回ArrayList的辅助函数:由于您知道大小,因此将只分配一次内存,而ArrayList对于通常的访问速度很快。 createForCopy需要返回一个演示 您是否考虑显示Eclipse编辑器模板?

浅克隆一个集合很容易,但是如果您想深度克隆,一个库可能比手工编码要好(因为您也想克隆该集合中的元素)。

就像这个答案一样,我使用了Cloner库,并针对XStream(可以先序列化然后反序列化"克隆")和二进制序列化对它进行性能测试。尽管XStream可以很快速地从xml序列化到/从xml序列化,但是Cloner的克隆速度要快得多:

0.0851 ms:xstream(通过序列化/反序列化克隆) 0.0223 ms:二进制序列化(通过序列化/反序列化克隆) 0.0017 ms:克隆器 *克隆一个简单对象(两个字段)的平均时间,并且没有默认的公共构造函数。运行10,000次。

除了快速之外,还有更多选择克隆器的原因:

对任何对象(甚至是那些您自己没有写过的对象)执行深层克隆 您不必在每次添加字段时都保持最新的clone()方法 您可以克隆没有默认公共构造函数的对象 与Spring一起使用 (优化)不会克隆已知的不可变对象(例如Integer,String等)

易于使用。例:

cloner.deepClone(anyObject);

我是布拉德提出的克隆库lib的创建者。这是一种无需编写任何额外代码即可克隆对象的解决方案(无需可序列化的对象或impl clone()方法)

正如Brad所说的那样,速度非常快,最近我上传了一个更快的版本。请注意,手动实现clone()方法将比克隆lib更快,但是再次,您将需要编写大量代码。

Cloner lib对我来说效果很好,因为我在流量非常大(每天约100万个请求)的站点的缓存实现中使用了它。缓存应为每个请求克隆大约10个对象。这是相当可靠和稳定的。但是请注意,克隆并非没有风险。可以将lib配置为println在开发期间克隆的每个类实例。这样,您可以检查它是否克隆了您认为应该克隆的内容-对象图可能非常深,并且可以包含对大量对象的引用。使用clone lib,您可以指示它不要克隆不需要的对象,即单例。

相关讨论 该库看起来不错,请稍后再检查... "尝试使用克隆库,您可以指示它不要克隆您不想要的对象",但是我不能,我如何要求它不克隆某些字段? 问候康斯坦丁诺斯。我正在使用您的库而不是Apache utils库(SerializableUtils的强制转换存在问题)。您的工作没有问题。做得好!。 我已经使用ur lib很长时间了,它的确很棒!谢谢! D:

深度克隆任意集合的一种通用方法是将其序列化为流,然后将其读回到新的集合中。您将为与旧对象没有任何关系的全新对象重新补水,但它们是相同的副本。

请查看Bruno的答案,以获得指向Apache Commons序列化实用程序类的链接,如果这是您决定采用的方法,这将非常有用。

相关讨论 序列化解决方案很好,但是我考虑了一些没有它的问题。我可以保证我的自定义对象将使用clone()方法正确地进行深克隆,但是我想要帮助它的对象将用于标准java类... 克隆的序列化方式很好,但是我有一些不在我控制范围内并且不可序列化的字段...

一种可能是使用序列化:

Apache Commons提供SerializationUtils

我使用了此克隆库,发现它非常有用。 由于它有一些局限性(我需要更精细的控制 克隆过程中:哪个领域,在什么背景下以及深入 应该被克隆等),我已经创建了它的扩展版本。 您可以通过在字段中添加注释来控制字段的克隆 实体类。

只是为了尝一尝,下面是一个示例类:

123456789101112131415161718192021222324public class CloneMePlease {     @Clone(Skip.class)     String id3 = UUID.randomUUID().toString();     @Clone(Null.class)     String id4 = UUID.randomUUID().toString();     @Clone(value = RandomUUID.class, groups=CustomActivationGroup1.class)     String id5 = UUID.randomUUID().toString();     @Clone.List({             @Clone(groups=CustomActivationGroup2.class, value=Skip.class),             @Clone(groups=CustomActivationGroup3.class, value=Copy.class)})     Object activationGroupOrderTest = new Object();     @Clone(LongIncrement.class)     long version = 1l;     @PostClone     private void postClone(CloneMePlease original, @CloneInject CloneInjectedService service){          //do stuff with the original source object in the context of the cloned object          //you can inject whatewer service you want, from spring/guice to perform custom logic here     } }

此处有更多详细信息: https://github.com/mnorbi/fluidity-cloning

还有一个休眠特定的扩展,以备不时之需。

先使用序列化再进行反序列化,但要注意,这种方法仅适用于无瞬态字段的Serializable类。此外,您的单身人士将不再是单身人士。

相关讨论 在运行时或在程序的单独运行之间使用序列化和反序列化来克隆内存对象是一个坏主意。有关为什么这样做的更多信息,请google:"为什么序列化和反序列化不好"。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3