6

I don't think that there is a way that is efficient (if at all) of doing this, but I figured I'd ask in case someone else knows otherwise. I'm looking to create my own Cache/lookup table. To make it as useful as possible, I'd like it to be able to store generic objects. The problem with this approach is that even though you can make a Collections.unmodifiableMap, immutableMap, etc, these implementations only prevent you from changing the Map itself. They don't prevent you from getting the value from the map and modifying its underlying values. Essentially what I'd need is for something to the effect of HashMap<K, ? extends Immutable>, but to my knowledge nothing like this exists.

I had originally thought that I could just return a copy of the values in the cache in the get method, but since Java's Cloneable interface is jacked up, you cannot simple call

public V getItem(K key){
    return (V) map.get(k).clone();
}
FuriousGeorge
  • 4,561
  • 5
  • 29
  • 52
  • Maybe you can achieve this with some reflection library that can do a deep copy of objects - this could be helpfull : http://stackoverflow.com/questions/2156120/java-recommended-solution-for-deep-cloning-copying-an-instance – Viktor K. Dec 24 '13 at 22:05
  • I should also add that this has to be efficient. I'm using the cache to speed up operations, and I'd hate to lose all of my compression savings to having to do a bunch of reflection hacks. – FuriousGeorge Dec 24 '13 at 22:24
  • I think the best way is to go with immutable objects as someone already mentioned in one of answers. I don't know about any nice method in java that can effectively create deep copy of object. Maybe there is a way how to return immutable object with AspectJ - but I am not very experienced with it - but maybe you can look for a solution also there. – Viktor K. Dec 24 '13 at 22:34

4 Answers4

5

Your thinking is good, and you're right that there's no built-in way of handling immutability.

However, you could try this:

interface Copyable<T> {
    T getCopy();
}

Then override the get() method to return copies instead of the value itself;

class CopyMap<K, V extends Copyable<V>> extends HashMap<K, V> {
    @Override
    public V get(Object key) {
        return super.get(key).getCopy();
    }
}

Then it's up to the implementation to return a copy of itself, rather than this (unless the class itself is immutable). Although you can't enforce that in code, you would be within your rights to publicly humiliate the programmer that doesn't conform.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • Yah I thought about doing it this way. I'd like to be able to accept *any* class, but I guess this will have to do. It kind of sucks though because now I can't simply use classes like Text, I have to wrap and/or extend it and then I run into performance issues. – FuriousGeorge Dec 25 '13 at 03:42
  • I'd suggest having both mutable and immutable objects/interfaces derive from a common "readable" interface that includes `asMutable`, `asNewMutable`, and `asImmutable` members. If an object wants a snapshot of something that it's never going to change, and if something else may ask it for a snapshot, it may as well ask for an immutable snapshot, so that when it's asked for a snapshot it can simply return a reference to the one it already has. – supercat Dec 26 '13 at 16:30
2

I'm looking to create my own Cache/lookup table.

Why not use Guava's cache?

The problem with this approach is that even though you can make a Collections.unmodifiableMap, immutableMap, etc, these implementations only prevent you from changing the Map itself. They don't prevent you from getting the value from the map and modifying its underlying values.

This is not something any collection can enforce for you. You need to make the classes themselves immutable. There is a hacky approach using Reflection (which can also be used to make a class mutable!), but really, you should avoid this and simply create classes that are immutable.

Amir Afghani
  • 37,814
  • 16
  • 84
  • 124
  • I agree, but I'm not the creator of every class. For example, I'm using this with MapReduce, but I want to be able to store Text values. I'd rather not have to take the penalty of creating a new String for every Text value, but at the same time, I can't make Text immutable – FuriousGeorge Dec 24 '13 at 22:22
1

There are other options for object cloning in Java: Making a copy of an object Dynamically?

Be aware though that deep cloning any object might be dangerous. The objects stored in this map must be i.e. isolated from each other, to make sure that whole object graph won't be copied when returning a single entry.

Community
  • 1
  • 1
Andrey Chaschev
  • 16,160
  • 5
  • 51
  • 68
1

There is no formal concept of "mutability" or "immutability" in the language. The compiler cannot tell whether a type is "mutable" or "immutable". To determine whether something is immutable, we humans have to examine every field and method of the class, and reason through the behavior of the methods to discover that none of them will alter the state of the object, then we call it "immutable". But there is no difference from the perspective of the language.

newacct
  • 119,665
  • 29
  • 163
  • 224