Java 深度克隆实用程序推荐

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/665860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 17:38:51  来源:igfitidea点击:

Deep clone utility recommendation

javaclone

提问by Juraj

Is there any utility for deep cloning for java collections:

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

  • Arrays
  • Lists
  • Maps
  • 数组
  • 列表
  • 地图

NOTE: prefer some solution without usage of serialization, but with use of Object.clone() method. I can be sure that my custom object will implement clone() method and will use only java-standard classes that are cloneable...

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

采纳答案by Cojones

I think the previous green answer was bad, why you might ask?

我认为以前的绿色答案很糟糕,你为什么要问?

  • It adds a lot of code
  • It requires you to list all fields to be copied and do this
  • This will not work for Lists when using clone() (This is what clone() for HashMap says: Returns a shallow copy of this HashMap instance: the keys and valuesthemselves are not cloned.) so you end up doing it manually (this makes me cry)
  • 它添加了很多代码
  • 它要求您列出要复制的所有字段并执行此操作
  • 当使用 clone() 时,这对 Lists 不起作用(这就是 HashMap 的 clone() 所说的:返回此 HashMap 实例的浅拷贝:键和值本身没有被克隆。)所以你最终手动完成(这使得我哭了)

Oh and by the way serialization is also bad, you might have to add Serializable all over the place (this also makes me cry).

哦,顺便说一句,序列化也很糟糕,你可能不得不到处添加 Serializable (这也让我哭了)。

So what is the solution:

那么解决方法是什么:

Java Deep-Cloning library The cloning libraryis a small, open source (apache licence) java library which deep-clones objects. The objects don't have to implement the Cloneable interface. Effectivelly, this library can clone ANY java objects. It can be used i.e. in cache implementations if you don't want the cached object to be modified or whenever you want to create a deep copy of objects.

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

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

Check it out at https://github.com/kostaskougios/cloning

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

回答by John Feminella

One general way to deep-clone an arbitrary collection is to serialize it to a stream, then read it back into a new collection.You'll be rehydrating completely new objects that don't have any relationship to the old ones, other than being identical copies.

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

Check out Bruno's answerfor a link to the Apache Commons serialization utility classes, which will be very helpful if this is the route you decide to take.

查看Bruno 的答案以获取Apache Commons 序列化实用程序类的链接,如果这是您决定采用的路线,这将非常有帮助。

回答by bruno conde

One possibility is to use serialization:

一种可能性是使用序列化

Apache Commons provides SerializationUtils

Apache Commons 提供了SerializationUtils

回答by Marko

Use serialization and then deserialization, but be aware that this approach works only with Serializable classes without transient fields. Also, your singletons will not be singletons anymore.

使用序列化然后反序列化,但请注意,此方法仅适用于没有瞬态字段的 Serializable 类。此外,您的单身人士将不再是单身人士。

回答by Aaron Digulla

All approaches to copy objects in Java have serious flaws:

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

Clone

克隆

  1. The clone() method is protected, so you can't call it directly unless the class in question overrides it with a public method.
  2. clone() doesn't call the constructor. Any constructor. It will allocate memory, assign the internal classfield (which you can read via getClass()) and copy the fields of the original.
  1. clone() 方法是受保护的,因此您不能直接调用它,除非相关类使用公共方法覆盖它。
  2. clone() 不调用构造函数。任何构造函数。它将分配内存,分配内部class字段(您可以通过 读取getClass())并复制原始字段。

For more issues with clone(), see item 11 of Joshua Bloch's book "Effective Java, Second Edition"

有关 clone() 的更多问题,请参阅 Joshua Bloch 的书“ Effective Java,第二版”的第 11 项

Serialize

连载

Serialize is even worse; it has many of the flaws of clone()and then some. Joshua has a whole chapter with four items for this topic alone.

序列化更糟;它有许多缺陷,clone()然后是一些。约书亚有一整章,仅针对这个主题就有四个项目。

My Solution

我的解决方案

My solution is add a new interface to my projects:

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

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

The code looks like this:

代码如下所示:

class Demo implements Copyable<Demo> {
    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...
    }
}

Unfortunately, I have to copy this code to all my objects but it's always the same code, so I can use an Eclipse editor template. Advantages:

不幸的是,我必须将此代码复制到我的所有对象,但它始终是相同的代码,因此我可以使用 Eclipse 编辑器模板。好处:

  1. I can decide which constructor to call and how to initialize which field.
  2. Initialization happens in a deterministic order (root class to instance class)
  3. I can reuse existing objects and overwrite them
  4. Type safe
  5. Singletons stay singletons
  1. 我可以决定调用哪个构造函数以及如何初始化哪个字段。
  2. 初始化以确定的顺序发生(根类到实例类)
  3. 我可以重用现有对象并覆盖它们
  4. 类型安全
  5. 单身人士保持单身人士

For standard Java types (like collections, etc), I use a utility class which can copy those. The methods have flags and callbacks, so I can control how deep a copy should be.

对于标准 Java 类型(如集合等),我使用了一个可以复制这些类型的实用程序类。这些方法有标志和回调,所以我可以控制副本的深度。

回答by Brad Cupit

Shallow cloning a collection is easy, but if you want to deep clone, a library will probably do you better than hand coding it (since you want to clone the elements insidethe collection as well).

浅克隆的集合是很容易的,但如果你想深克隆,图书馆可能会做你比手更好的编码它(因为要克隆的元素里面集合为好)。

Just like this answer, I've used the Cloner libraryand specifically performance tested it against XStream (which can 'clone' by serializing then deserializing) and binary serialization. Though XStream is very fast at serializing to/from xml, Cloner is much faster at cloning:

就像这个答案一样,我使用了Cloner 库,并专门针对 XStream(可以通过序列化然后反序列化来“克隆”)和二进制序列化对它进行了性能测试。尽管 XStream 在序列化到 xml 或从 xml 序列化方面非常快,但 Cloner 在克隆方面要快得多:

0.0851 ms : xstream (clone by serializing/deserializing)
0.0223 ms : binary serialization (clone by serializing/deserializing)
0.0017 ms : cloner
* average time to clone a simple object (two fields) and no default, public constructor. Run 10,000 times.

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

In addition to being fast, here are more reasons to choose cloner:

除了速度快之外,还有更多选择克隆器的理由:

  1. performs a deep clone of any object (even those you don't write yourself)
  2. you don't have to keep your clone() method up-to-date each time you add a field
  3. you can clone objects that don't have a default public constructor
  4. works with Spring
  5. (optimization) doesn't clone known immutable objects (like Integer, String, etc.)
  6. easy to use. Example:

    cloner.deepClone(anyObject);

  1. 执行任何对象的深度克隆(即使是您自己不编写的对象)
  2. 您不必每次添加字段时都使 clone() 方法保持最新
  3. 您可以克隆没有默认公共构造函数的对象
  4. 与春天一起工作
  5. (优化)不会克隆已知的不可变对象(如整数、字符串等)
  6. 便于使用。例子:

    cloner.deepClone(anyObject);

回答by Konstantinos Kougios

I am the creator of the cloner lib, the one that Brad presented. This is a solution for cloning objects without having to write any extra code (no need for serializable objects or impl clone() method)

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

It's quite fast as Brad said, and recently I uploaded a version which is even faster. Note that manually implementing a clone() method will be faster than clone lib, but then again you'll need to write a lot of code.

正如布拉德所说,它非常快,最近我上传了一个更快的版本。请注意,手动实现 clone() 方法将比 clone lib 更快,但您将需要编写大量代码。

Cloner lib has worked quite well for me since I am using it in a cache implementation for a site with very heavy traffic (~1 million requests/day). The cache should clone approximately 10 objects per request. It is quite reliable and stable. But please be aware that cloning is not without risk. The lib can be configured to println every class instance that it clones during dev. This way you can check if it clones what you think it should clone - object graphs can be very deep and can contain references to a surprisingly large amount of objects. With clone lib, you can instruct it to not clone the objects that you don't want, i.e. singletons.

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

回答by Norbert Madarász

I've used this cloninglibrary and found it quite useful. Since it had a few limitations (I needed finer grained control over the cloning process: which field, in what context and how deeply should be cloned etc.), I've created an extended version of it. You control the cloning of the fields by annotating them in the entity class.

我使用过这个克隆库,发现它非常有用。由于它有一些限制(我需要对克隆过程进行更精细的控制:哪个字段、在什么上下文中以及应该克隆多深等),我创建了它的扩展版本。您可以通过在实体类中注释字段来控制字段的克隆。

Just to get a flavour of it, here is an example class:

只是为了了解它,这是一个示例类:

public 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
    }
}

More details here: https://github.com/mnorbi/fluidity-cloning

更多细节在这里:https: //github.com/mnorbi/fluidity-cloning

There is also a hibernate specific extension in case one needs it.

如果需要,还有一个特定于休眠的扩展。