什么时候Java对象可以序列化而不是Cloneable?

fin*_*nnw 7 java serialization serializable deep-copy cloneable

如果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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我经常遇到像这样的第三方库类,并采用上面那样的黑客攻击.我甚至ObjectOutputStream偶尔会延长副本的颜色.它从来没有造成严重的问题,除了效率低(编码/解码速度慢,临时序列化图形可能消耗大量内存.)

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

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


相关:使用Java复制对象

Bri*_*new 5

我宁愿使用复制构造函数而不是使用上面的机制.您可以更精细地定义要深入或浅层复制的内容,并使对象的复制与对象的序列化不同.复制构造函数可以(例如)允许两个对象共享对主对象的引用,而这可能不适合于通过网络序列化和传输的对象.

请注意,该Cloneable方法现在被广泛认为是破碎的.有关更多信息,请参阅Joshua Bloch的这篇文章.特别是它没有clone()方法!


Sea*_*wen 1

嗯,您是说序列化机制是间接“克隆”对象的一种方法。这当然不是它的主要功能。它通常用于让程序通过网络传输对象,或存储并稍后读取它们。您可能期望以这种方式使用对象,并实现 Serialized,而不期望代码在本地克隆对象,并且不实现 Cloneable。

代码通过序列化解决这个问题的事实表明,代码正在以作者不希望的方式使用对象,这可能是作者或调用者的“错误”,但这并不意味着一般情况下可序列化和可克隆一起走。

另外,我不确定clone()是否“损坏”,以及正确实现起来是否困难。恕我直言,复制构造函数更容易使用并且正确。