1

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

我已经编写了一个实用程序类,它通过内存序列化来实现这一点,但后来注意到它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();

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

4

1 回答 1

4

有一个显着的区别 -Collections.nCopies不复制对象!它只返回一个List包含n条目,所有这些都是提供的对象(检查源!)。对您从该列表中选择的任何内容所做的任何更改都将反映在原始对象中。所以这段代码:

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。哎呀。

序列化往返不是一个坏主意。另一种方法是 using Cloneable,不幸的是,它有点坏了。Cloneable没有声明clone(),但它被声明为protectedinObject,所以你必须通过反射来调用它。

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

于 2012-07-16T18:13:28.823 回答