I find my self having to export references to keys in an underlying Java collections map. I don’t want to give out references to the actual key objects but copies of them to ensure that nobody fiddles with the values and messes up the map. So I need to create a copy of an arbitrary generic type.
I already wrote a utility class that does this through in memory serialisation, but then noticed that Collections.nCopies also gives me copies of things.
So just to give some idea of what I am doing, I need to for instance access the next (higher/lower) key value given some other key value.
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()
}
}
So the question is if it is better to copy the objects with
T copy = Collections.nCopies(1,item).get(0)
or to serialise the object and then deserialise it
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 quick test with copying a Long shows that the Collections.nCopies is faster (0 ms / 8 ms). Is there some caveat to that method that I’m not able to think about at this late hour though, or can you think of an even better way of getting a copy of the keys?
There is a significant difference –
Collections.nCopiesdoesn’t copy the object! It just returns aListcontainingnentries, all of which are the provided object (check the source!). Any changes made to anything you pick out from that list will be reflected in the original object. So this code:will print
13, not0. Oops.A serialization roundtrip isn’t a bad idea. An alternative is using
Cloneable, which unfortunately is kind of broken.Cloneabledoesn’t declareclone(), but it is declared asprotectedinObject, so you have to invoke it by means of reflection.Personally, I’d prefer to use immutable objects in your situation, if possible.