Java Map for unique object instances?

Viewed 407

A library I use contains a certain object type, LackingObject (some type), which lacks an attribute of type Ext (some type). If I was able to change the LackingObject class, I would simply add an attribute with type Ext, but LackingObject cannot be changed, nor extended. What I'd do now in languages like C or C++ is to create a Map that maps LackingObjects to Exts, which, in Java, would (somewhat equivalently) look like

Map<LackingObject, Ext> object_extension = new HashMap<>();

so whenever I encounter a LackingObject in my code for the first time, I can call

LackingObject o = ...;
Ext value = compute_value_for(o, ...);
object_extension.put(o, value);

and then, to recall that added attribute, I would call

Ext resolved = object_extension.get(o);

This however will not work, as the default HashMap behavior is to map the results of Object::hashCode, not Objects, to values, so if I had two (apart from the Ext value) equal LackingObjects, they could not both be a unique key in a java.util.HashMap.

The question: In Java, is there at least one of the following:

  • a way to let the standard libraries map object instances to values?

  • a way to receive an unique identifier for an object instance?

I found a 7 year old post somewhat related to this topic, but I hope things have changed during the years.

The final resort would be to create a wrapper class,

class Wrapper{
    LackingObject o;
    Ext v;
}

but that overall seems to me like an inferior solution, as we would be adding a potentially redundant new object type to the project structure, instead of just adding a few statements.

(Unrelated to the topic, as this part of the problem is specific to my current condition, but this 'inferior solution' would also require me to change a lot of already existing source code, which I would happily avoid, if possible.)

2 Answers

You can use IdentityHashMap for this purpose. According to its documentation:

This class implements the Map interface with a hash table, using reference-equality in place of object-equality when comparing keys (and values). In other words, in an IdentityHashMap, two keys k1 and k2 are considered equal if and only if (k1==k2). (In normal Map implementations (like HashMap) two keys k1 and k2 are considered equal if and only if (k1==null ? k2==null : k1.equals(k2)).)
This class is not a general-purpose Map implementation! While this class implements the Map interface, it intentionally violates Map's general contract, which mandates the use of the equals method when comparing objects. This class is designed for use only in the rare cases wherein reference-equality semantics are required.

System.identityHashCode

Digging in the guts of IdentityHashMap (obtained thanks to Answer by Unmitigated), I found an answer to the partial question:

What is the way to receive a unique identifier for an object instance?

…with the key being: System.identityHashCode

with the signature of

int identityHashCode(Object);

To quote the Javadoc:

Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object's class overrides hashCode(). The hash code for the null reference is zero.

Related