Getting A Java Object’s Reference ID
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))
Absolutely No Machete Juggling is a blog about software, programming, computers, and me. I'm a programmer working in Colorado, mostly with Java and Ruby. 



david van brink:
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.
2 January 2009, 2:17 amLorenzo:
This saved my day! Thanks :-)
2 March 2009, 11:46 amanonymous:
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) { ; }
}
}
20 March 2009, 6:01 pm}
redmaniac:
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.
22 March 2009, 12:22 pmDom Sparks:
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…
6 May 2009, 9:35 amPetr Smid:
hashCode gives you hash code and NOT any unique ID! Hash code can have colisions. Btw. see API documentation of Object.hashCode().
21 May 2009, 8:48 amWhatmore I see no reason to override hashCode() when overriding toString(). ToString method is not ment to return hashCode… just String describing the current instance.
infinity0:
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.
14 July 2009, 6:13 am