UPDATE: A number of commenters have pointed out that I’m totally wrong here. Please don’t do this.

When you take an object that has not defined a toString method, it prints out strings that look like these:

Object@3e25a5
Car@19821f

Many people believe that this is the memory location of the object, which isn’t really accurate, as it’s the reference ID. It is, however, a string that uniquely identifies the object in memory, so the misconception is understandable.

A friend recently asked me if there was any way to get that “address” on an object that has overridden toString. Once toString has been overridden, calling it will bypass this default implementation.

Since his internet search didn’t pull anything up, I figured I’d blog about the answer to his conundrum in case anyone else is ever curious about it.

It may be surprising, but calling hashCode() actually gives you this value. The hashCode method doesn’t hash the actual object by it’s value, but by it’s identity, meaning its reference ID.

To illustrate this simply, take a look at the following code snippet. It creates two identical objects, then adds them to a HashMap, and prints out the size of the HashMap.

Car car1=new Car("Chevy", "Blazer");
Car car2=new Car("Chevy", "Blazer");

AbstractMap<Car, String> map=new HashMap<Car, String>();
map.put(car1, "Got it");
map.put(car2, "Got it");

System.out.println("Size is: "+map.size());

HashMap works by calling hashCode() on the objects going into the map. You might expect for the size to be 1, since the two cars are the same. However, they do not have the same hashCode, because hashCodes are, by default, identity-based. Since the two objects take up two unique spots in memory (as they were instantiated separately), they have different hashCodes, and thus the size of the map is 2.

This means that you can get the reference ID, the thing after the @ in default toString() implementations, simply by calling hashCode() on the object. It comes back as an int, but it has the same value as the hexadecimal string would in the default toString() implementation.

However, it’s really not a good idea to override toString() without also overriding hashCode() and equals(), so it stands to reason hashCode will be overridden with a value-based hashing scheme in whatever class you’re working with.

Fear not, however, as the System object will actually give you access to the identity-based hashcode on any object, even if the class it is an instance of has overridden hashCode().

You can also handily convert an integer to a hex string using the Integer class, so you can get the value that would come after the @ in a default toString() implementation by calling this:

Integer.toHexString(System.identityHashCode(object))

13 Responses to “Getting A Java Object’s Reference ID”

  1. Ramakrishna says:

    Thanx a lottttttt Frank….its working fine….i was searching for unique ids for objects.toHexString is better convincing….

  2. vladimir knajtner says:

    Clumsy and inefficient. Oracle/Sun guys, have you ever tried to use this tool and take heap dumps on a very large (64bit) VM memory? It takes hours to do something like that. Instead your MemoryLeakClass, you usually find a String or some other simple object that has highest object count. Sorry, but this toolkit works only on a mickey mouse hello world examples, not in real life. Instead, how about exposing a memory profiling tools via JRE/JDK that can be used via debugger? For example, providing Class.allInstances() or Object.allOwners() would be a great and quick way to debug most of memory related issues. How about getting an expression profiler that can be launched from debugger? All this stuff has been a part of grand daddy Smalltalk for decades, why not implement it in Java?

  3. Frank says:

    Further to my comment, here is a little piece of code that shows how likely it is indeed that dissimilar objects with the same hash code are produced.

    import java.util.Hashtable;
    import java.util.Map;

    public class HashcodeTest{
    static class DummyObject extends Object { }

    public static void reportClash(DummyObject obj1, DummyObject obj2) {
    System.out.println(“obj1.hashCode() = ” + obj1.hashCode());
    System.out.println(“obj2.hashCode() = ” + obj2.hashCode());
    System.out.println(“(obj1 == obj2) = ” + (obj1 == obj2) + ” (!)”);
    }

    public static void main(String[] args) {
    Map map = new Hashtable();
    for (int count = 1; true; count++) {
    DummyObject obj = new DummyObject();
    if (map.containsKey(obj.hashCode())) {
    System.out.println(
    “Clash found after instantiating ” + count + ” objects.”);
    reportClash(map.get(obj.hashCode()), obj);
    System.exit(0);
    }
    map.put(obj.hashCode(), obj);
    }
    }
    }

    It repetitively constructs objects, stores them in a Map using their hash code as a key, and detects when a key has already been used and thus two different objects with the same hashCode() result coexists. On my system (Java 6, Ubuntu 10.04) this happens only after 1756 instantiations. The mathematically-inclined might work out the average number of instantiations as a special instance of the birthday paradox, supposing hashCode() aims to be randomly distributed. This confirms, at least for me, that hashCode() is not even in *practical terms* a useful facility to serve as an object identity.

    PS: If anyone wants to share some ideas please feel free to get in touch, my email is on my University of York website (http://www-users.cs.york.ac.uk/~zeyda/).

    Best wishes,
    Frank

  4. Frank says:

    PS: “if so returns null” should be “if so returns 0″.

    PPS: predictable in a sense as independent of the usage pattern of the class. Maybe static is a better word…

  5. Frank says:

    Yes, sorry to say but your analysis seems a bit confused. First of all, toString() has no significance here as it does not have any notable contract. Also needless to say it is a bad idea to make assumptions about its value – best to leave it out of the game for its lack of a precise semantics.

    Secondly, as the previous couple of posts already state, there is no requirement for hashCode() to yield a unique identifier for an object; a quick look at the method description in the Object class in the Java API confirms this.

    http://download.oracle.com/javase/6/docs/api/

    But, of course, we *can* obtain a unique identifier for an object: its simply its object reference. The only problem is that we cannot do much with it :D. I.e. we can only check if references are equal or not, but not convert them into numbers as far as I am aware.
    This seems only restrictive I believe if we attempt to implement something like a “universal comparator” that works for any kind of object, namely because we cannot do arithmetic comparison with references that would easily induce a total order that the comparator could use to fulfill its contract. Despite I think this problem can be solved.

    A hint: one might implement a comparator that first checks if o1.equals(o2) and if so returns null. If not, it stores both objects in a map by assigning consecutive numbers to them when they are first encountered. This induces a total order that the comparator may use to fulfill its contract. The order is not a priori fixed or predictable, but in some case we don’t actually care about that. Also, unlike something like: o1.hashCode() < o2.hashCode() ? 1 : -1 it is consistent with equals. Any more thoughts on this are welcome.

    PS: Just my two pence.

    Frank

  6. Dontell says:

    “UPDATE: A number of commenters have pointed out that I’m totally wrong here. Please don’t do this.”

    This is so funny, really :-D.

  7. infinity0 says:

    The blog post is *wrong*. System.identityHashCode() does NOT generate unique IDs for objects. Its only guarantee is that if the codes are different the objects are different, not the other way round. If you rely on this behaviour, your program will see very weird bugs every once in a while.

  8. Petr Smid says:

    hashCode gives you hash code and NOT any unique ID! Hash code can have colisions. Btw. see API documentation of Object.hashCode().
    Whatmore I see no reason to override hashCode() when overriding toString(). ToString method is not ment to return hashCode… just String describing the current instance.

  9. Dom Sparks says:

    Agree with the previous comment, and in fact I’m currently looking at some code which is problematic because System.identityHashCode() is returning the same hashcode for two distinct objects. Although I’m sure that previous versions of Sun’s JDK would always produce unique values, it seems that in JDK1.5 (which is what I’m currently using) the value is not necessarily unique. I’m having to change my code so that I generate my own ids for objects as and when they are created, rather than using System.identityHashCode() as an identifier…

  10. redmaniac says:

    You should be careful with taking the Object.hashCode for a reference id: According to the Sun Java API the class ‘Object’ implements hashCode in such a way that it really does distinguish any two objects. However, it also states that this behavior is by no means required by the Java Standard, i.e. another java implementation than Sun’s might behave differently in that issue while still being a “correct” java implementation.

  11. anonymous says:

    I have been looking to get/print such info too. And for a bit, the explanation here seemed convincing. However, when I wrote a small program and when I force the VM to do a “full thread dump” (by hitting Ctrl-Brk on keyboard, or by running jmap and jhat, and look at the output, the instance addresses are totally different. Try it out with this simple program. If you look at the “full thread dump”, look for the main-thread stack and look for what object is in locked state – corresponding to synchronized state here.

    Hope somebody has a way of really printing real object references.

    public class Foo
    {
    private String sName;

    Foo()
    {
    ;
    }

    Foo(String s)
    {
    sName = s;
    }

    public static void main(String[] args) {
    Foo f1 = new Foo(“Hello”);
    Foo f2 = new Foo(“Hello”);

    Object syncObj = null;
    for(int i=0; i < 50000; i++) {
    System.out.println(“f1: ” + “0x” + Integer.toHexString(System.identityHashCode(f1)));
    System.out.println(“f2: ” + “0x” + Integer.toHexString(System.identityHashCode(f2)));
    System.out.println(“Class f1: ” + “0x” + Integer.toHexString(System.identityHashCode(f1.getClass())));

    try {
    int j = i % 3;
    switch (j) {
    case 0:
    syncObj = f1;
    System.out.println(“Synchronizing on f1 obj”);
    break;
    case 1:
    syncObj = f2;
    System.out.println(“Synchronizing on f2 obj”);
    break;
    case 2:
    syncObj = f1.getClass();
    System.out.println(“Synchronizing on Class obj”);
    break;
    default:
    syncObj = null;
    break;
    }
    synchronized(syncObj) {
    Thread.sleep(10000);
    }
    }
    catch (Exception e) { ; }
    }

    }
    }

  12. Lorenzo says:

    This saved my day! Thanks :-)

  13. Thank you!

    That clears up a mystery to me. Also solves my problem at hand (where I wanted to print a unique-ish id…)

    Going further, in Eclipse, the debugger shows a different object id. Stuff like String[id=73] an other low numbers… any idea where *that* comes from? Guessing it’s unique to its debugger (if it overrides all object-creation) or in the debug API.

    ToHexString is AOK. Thanks again.

Leave a Reply