On Monday, January 3, 2011 10:42:28 AM UTC+1, sinelaw wrote:
Thomas - Also, regarding your suggestions the wrapper object is in
fact what I'm using for now (my second post mentioned that).
You're subclassing HashMap, not wrapping a Map.
But I
don't see how a sentinel would help me in my real use case of a
complex graph of circular references between maps, since it will be
hard to keep track of which sentinel represents which map.
yes, sorry I misread your initial 4-lines repro case.
So , I think you'd to use a wrapper object that implements equals and hashCode independently of the content of the wrapped map; something like:
// do not implement Map, as it would break the contract for Map.hashCode and Map.equals
class Wrapper<K, V> {
private final Map<K, V> map;
public Wrapper(Map<K,V> map) {
this.map = map;
}
public final Map<K, V> get() {
return map;
}
@Overrides
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Wrapper) {
// use identity comparison: 2 wrappers are equal if they wrap the very same map, independently of its content
return map == ((Wrapper) obj).map;
}
return false;
}
@Overrides
public int hashCode() {
// not the best for performances, but at least does not violates the Object.hashCode/equals contract
return 31;
}
}
Best would probably be to use a subclass of Map that keeps a reference to the "key" object so as to maintain a 1:1 bidirectional relationship between maps and their keys (and that way, you don't even have to implement the hashCode and equals methods, the default implementations are sufficient):
class MapWithKey<K, V> extends HashMap<K, V> {
public final class Key<K, V> {
public MapWithKey<K, V> getMap() {
return MapWithKey.this;
}
}
private final Key<K, V> key = new Key<K, V>();
public final Key<K, V> getKey() { return key; }
}
Then, instead of testMap2.put(testMap, null), you'd use testMap2.put(testMap.getKey(), null);