如果 Java 类实现了 Serializable 接口但没有公共 clone() 方法,通常可以像这样创建深拷贝:

class CloneHelper {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            byte[] bytes = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            T copy = (T) ois.readObject();
            ois.close();
            return copy;
        } catch (ClassNotFoundException ex) {
            // Shouldn't happen
            throw new Error(ex);
        } catch (IOException ex) {
            // Probably a bug in T's custom serialization methods
            throw new RuntimeException(ex);
        }
    }
}

我经常遇到这样的第三方库类,并求助于像上面这样的黑客。我什至还延长了 ObjectOutputStream 有时会使副本变浅。除了效率低下之外,它从来没有造成严重的问题(编码/解码速度慢,并且临时序列化图可能会消耗大量内存。)

如果使用这种技术不安全,则该类可能不应该被声明 Serializable.

所以我想知道的是,如果你的班级是 Serializable, ,什么可能会阻止您定义公共 clone() 方法(使用 Cloneable 接口还是复制构造函数?)


有关的: Java 中复制对象

有帮助吗?

解决方案

好了,你说的序列化机制是一个方法来“克隆”间接对象。当然,这是不是它的主要功能。它通常用来让通过网络或存储发送对象的程序,并在以后读。您可能希望一个对象要使用这种方式,并且实现Serializable接口,虽然不指望代码克隆本地对象,并没有实现Cloneable。

这代码是通过序列化工作解决这个问题的事实表明该代码使用的方式对象笔者没有打算,这可能是无论是作者或呼叫者的“过失”,但它并不意味着在一般串行化和去Cloneable的一起。

另外,我不知道的clone()是“破”尽可能棘手的正确实施。复制构造是更自然的使用,并得到正确恕我直言。

其他提示

我宁愿使用一个拷贝构造,而不是使用上面的机制。您可以更精细地定义什么是深或浅拷贝,使的复制的对象从的系列化的的对象不同的。复制构造可(例如)允许两个对象共享到主对象的引用,而这可能并不适合于通过网络和序列化发送的对象。

注意,Cloneable方法被广泛现在被视为损坏。请参见与约书亚布洛赫这篇文章以获取更多信息。特别是它不具有clone()方法!

Brian的约Cloneable的点是非常好的,但即使Cloneable的工作权利,仍然有情况下,您可能希望对象是可序列化,但不可复制。

如果对象具有的处理的范围之外的唯一标识,如数据库记录的内存中表示,你不希望它是可复制的,因为这是等同于使具有相同属性的一个新的记录,包括像数据库的关键,这是几乎从来没有正确的事情身份相关的属性。与此同时,你可能拆分为稳定性或其他原因,多个进程的系统,所以你可能有一个过程谈论到数据库,并产生这些“实体”的对象(见“领域驱动设计”,由埃里克·埃文斯更多上保持在数据支持的应用对象身份相干性),但一个单独的进程可以使用这些对象来执行业务逻辑的操作信息。实体对象将需要是可序列化它能够从一个进程传递到另一个。

我认为序列化和Cloneable的接口应该被用于完全不同的目的。如果你有一个复杂的类,然后实现他们每个人是不那么容易。因此,在一般情况下,这取决于目的。

一与序列化的最大问题是,它们不能容易地作出不可改变的。 序列化迫使你做出了妥协这里。

我很想创建复制构造向下的对象图。它只是有点更繁重的工作要做。

这令我有点危险,因为有一些陷阱序列化的,(虽然他们大多是不可能的,我还是想测试他们,如果我是在3D第三方库序列化对象)。不可能是一个常见的问题,但它可能有一个对象与volatile变量,因为它的状态的一部分,可能是克隆操作(不,这是一个很好的设计,只是有可能)的一部分,这样的现场不会被复制的序列化/反序列化过程。我想到的另一个问题是枚举,常量,并得到这样的事情多份,如果你不跟他们反序列化过程处理的可能性。

再次边缘情况,但你要注意的东西。

我刚刚想到了另一种情况 - 当它是 枚举.

或者更一般地说,当你的类实现 readResolve. 。这意味着您从中返回的对象 readObject 与从流中读取的对象不同,因此它不一定是最初写入流的对象的副本。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top