最好是在没有工厂的情况下克隆Java中的通用对象的有效方法

时间:2012-07-16 17:46:56

标签: java generics cloning

我发现自己必须导出对基础Java collections地图中的键的引用。我不想提供对实际关键对象的引用,而是给它们的副本,以确保没有人摆弄这些值并弄乱地图。所以我需要创建一个任意泛型类型的副本。

我已经编写了一个实用程序类,通过内存序列化来实现这一点,但后来注意到Collections.nCopies也给了我复制的东西。

所以,只是想知道我在做什么,我需要例如在给定其他键值的情况下访问下一个(更高/更低)键值。

public class MapWrapper<T, K extends Comparable<K>>
    implements OtherThing<T, K>
{
    public K next (K current) {
        return ... cloned next highest key as per NavigableMap.higherKey()
    }
}

所以问题是,用

复制对象是否更好
T copy = Collections.nCopies(1,item).get(0)

或序列化对象然后反序列化

final ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream();
final ObjectOutputStream outputStream = new ObjectOutputStream(outputBuffer);
outputStream.writeObject(item);
outputStream.close();

final ByteArrayInputStream inputBuffer = new ByteArrayInputStream(buffer);
final ObjectInputStream inputStream = new ObjectInputStream(inputBuffer);T copy = null;
T item = null;
try {
    copy = (T)inputStream.readObject();
} catch (ClassNotFoundException e) {
    Logger.getLogger(SerialisationService.class.getName()).log(Level.WARNING, null, e);
}

inputStream.close();
inputBuffer.close();
outputBuffer.close();

复制Long的快速测试表明Collections.nCopies更快(0毫秒/ 8毫秒)。是否有一些警告我不能在这么晚的时候考虑这个方法,或者你能想到一个更好的方法来获得密钥副本吗?

1 个答案:

答案 0 :(得分:4)

存在显着差异 - Collections.nCopies不会复制对象!它只返回包含List条目的n,所有条目都是提供的对象(check the source!)。对从该列表中选择的任何内容所做的任何更改都将反映在原始对象中。所以这段代码:

Point original = new Point(0, 0);
Point supposedCopy = Collections.nCopies(1, original).get(0);
supposedCopy.x = 13;
System.out.println("x = " + original.x); 

将打印13,而不是0。糟糕。

序列化往返不是一个坏主意。另一种方法是使用Cloneable,遗憾的是它有点破碎。 Cloneable未声明clone(),但它是declared as protected in Object,因此您必须通过反思来调用它。

就个人而言,如果可能的话,我更愿意在你的情况下使用不可变对象。