253

When a class in Java doesn't override hashCode(), printing an instance of this class gives a nice unique number.

The Javadoc of Object says about hashCode():

As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects.

But when the class overrides hashCode(), how can I get its unique number?

serv-inc
  • 29,557
  • 9
  • 128
  • 146
ivan_ivanovich_ivanoff
  • 18,003
  • 24
  • 78
  • 100
  • 37
    Mostly for 'debugging' reasons ;) To be able to say: Ah, same object! – ivan_ivanovich_ivanoff May 26 '09 at 10:07
  • 6
    For this purpose the System.identityHashcode() is likely of some use. I wouldn't rely on it for implementing code functionality, however. If you want to identify objects uniquely, you could use AspectJ and code-weave in a unique id per created object. More work, though – Brian Agnew May 26 '09 at 10:38
  • 9
    Just keep in mind that hashCode is NOT guaranteed to be unique. Even if the implementaiton uses memory address as the default hashCode. Why is it not unique? Because objects get garbage collected, and memory is reused. – Igor Krivokon May 26 '09 at 10:42
  • 1
    Note this CR for API docs: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6321873 – Tom Hawtin - tackline May 26 '09 at 10:43
  • 8
    If you want to decide, if two objects are the same use == instead of hashCode(). The latter is not guaranteed to be unique, even in the original implementation. – Mnementh May 26 '09 at 10:51
  • Just generate your own unique ID during instantiation via a `static AtomicInteger()` – b1nary.atr0phy Jun 09 '13 at 16:31
  • 9
    None of the answers answer the real question because they get tangled up in discussing hashCode(), which was incidental here. If I look at reference variables in Eclipse, it shows me a unique immutable "id=xxx." How do we get to that value programmatically without having to use our own id generator? I want access to that value for debugging purposes (logging) in order to identify distinct instances of objects. Does anybody know how to get your hands on that value? – Chris Westin Apr 09 '15 at 20:13
  • @Mnementh for debugging sometimes objects are equal but you'd still like to know if they are different objects, probably better to refer to those 2 objects as _equivalent_ rather than _the same_ - although I'm not sure the correct terminology in computer-speak but in English that makes the most sense. Otherwise it can be confusing – ycomp Nov 08 '17 at 08:50
  • @ycomp:In Java == compares references, which means it is only true for the same object. To compare the equalness, you should use the method euqals(). Say a= new Integer(1);b = new Integer(1); a==b is false while a.equals(b) is true. – Mnementh Nov 09 '17 at 10:17
  • @Mnementh sorry my apologies, using kotlin as my main language really fried my brain when it comes to java (when I'm tired) – ycomp Nov 09 '17 at 11:11
  • Does your unique identifier need to be an integer/String ID? Why not just use the `Object` instance itself? It's basically a unique pointer to anything that inherits from an object. – MasterHD Jun 28 '19 at 11:02

10 Answers10

379

System.identityHashCode(yourObject) will give the 'original' hash code of yourObject as an integer. Uniqueness isn't necessarily guaranteed. The Sun JVM implementation will give you a value which is related to the original memory address for this object, but that's an implementation detail and you shouldn't rely on it.

EDIT: Answer modified following Tom's comment below re. memory addresses and moving objects.

joseph
  • 1,382
  • 13
  • 28
Brian Agnew
  • 254,044
  • 36
  • 316
  • 423
  • Let me guess: it's not unique, when you have more than 2**32 objects in same JVM? ;) Can you point me to some place, where the non-uniqueness it is described? Thanx! – ivan_ivanovich_ivanoff May 26 '09 at 10:10
  • 9
    It doesn't matter how many objects there are, or how much memory there is. Neither hashCode() nor identityHashCode() is required to produce a unique number. – Alan Moore May 26 '09 at 10:33
  • 12
    Brian: It's not the actual memory location, you happen to get a rehashed version of an address when first computed. In a modern VM objects will move about in memory. – Tom Hawtin - tackline May 26 '09 at 10:41
  • 3
    So if an object is created at memory address 0x2000, then is moved by the VM, then an other object is created at 0x2000, will they have the same `System.identityHashCode()`? – lmat - Reinstate Monica Jun 07 '13 at 22:54
  • 16
    Uniqueness isn't **guaranteed** at all ... for a practical JVM implementation. Guaranteed uniqueness requires either no relocation / compaction by the GC, or a big and expensive data structure for managing the hashcode values of live objects. – Stephen C Jul 24 '13 at 03:59
  • How then is `Object.hashChode()` guaranteed to remain the same through out execution life for the same instance. if this API returns what the 'original' `hashCode()` would have returned? – juanmf Oct 26 '20 at 22:28
29

The javadoc for Object specifies that

This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.

If a class overrides hashCode, it means that it wants to generate a specific id, which will (one can hope) have the right behaviour.

You can use System.identityHashCode to get that id for any class.

Valentin Rocher
  • 11,343
  • 43
  • 59
9

hashCode() method is not for providing a unique identifier for an object. It rather digests the object's state (i.e. values of member fields) to a single integer. This value is mostly used by some hash based data structures like maps and sets to effectively store and retrieve objects.

If you need an identifier for your objects, I recommend you to add your own method instead of overriding hashCode. For this purpose, you can create a base interface (or an abstract class) like below.

public interface IdentifiedObject<I> {
    I getId();
}

Example usage:

public class User implements IdentifiedObject<Integer> {
    private Integer studentId;

    public User(Integer studentId) {
        this.studentId = studentId;
    }

    @Override
    public Integer getId() {
        return studentId;
    }
}
MrB
  • 757
  • 6
  • 26
ovunccetin
  • 7,673
  • 4
  • 38
  • 45
6

Maybe this quick, dirty solution will work?

public class A {
    static int UNIQUE_ID = 0;
    int uid = ++UNIQUE_ID;

    public int hashCode() {
        return uid;
    }
}

This also gives the number of instance of a class being initialized.

John Pang
  • 1,952
  • 19
  • 23
  • 4
    This assumes that you have access to the source code of the class – pablisco Jan 20 '15 at 17:35
  • If you cannot access the source code, just extend from it and use the extended class. Simply quick, easy and dirty solution but it works. – John Pang Jan 26 '15 at 07:34
  • 1
    it doesn't always work. The class could be final. I think `System.identityHashCode` is a better solution – pablisco Jan 26 '15 at 11:40
  • 3
    For thread-safety, one could use `AtomicLong` as in [this answer](http://stackoverflow.com/a/8939049/1143274). – Evgeni Sergeev Mar 11 '16 at 04:25
  • If the class is loaded by a different classloader it will have different UNIQUE_ID static variables, am I correct? – cupiqi09 Mar 04 '20 at 10:04
  • This answer doesn't intended to work in all cases, such as different class loader. Just provide a simple, quick solution that may help. If your situation is more complicated, should consider alternative answer. Thanks. – John Pang Mar 19 '20 at 06:57
4

If it's a class that you can modify, you could declare a class variable static java.util.concurrent.atomic.AtomicInteger nextInstanceId. (You'll have to give it an initial value in the obvious way.) Then declare an instance variable int instanceId = nextInstanceId.getAndIncrement().

Aaron Mansheim
  • 405
  • 3
  • 11
4

I came up with this solution which works in my case where I have objects created on multiple threads and are serializable:

public abstract class ObjBase implements Serializable
    private static final long serialVersionUID = 1L;
    private static final AtomicLong atomicRefId = new AtomicLong();

    // transient field is not serialized
    private transient long refId;

    // default constructor will be called on base class even during deserialization
    public ObjBase() {
       refId = atomicRefId.incrementAndGet()
    }

    public long getRefId() {
        return refId;
    }
}
Howard Swope
  • 423
  • 3
  • 9
4
// looking for that last hex?
org.joda.DateTime@57110da6

If you're looking into the hashcode Java types when you do a .toString() on an object the underlying code is this:

Integer.toHexString(hashCode())
Frankie
  • 23,189
  • 10
  • 74
  • 112
1

I had the same issue and was not satisfied with any of the answers so far since none of them guaranteed unique IDs.

I too wanted to print object IDs for debugging purposed. I knew there must be some way to do it, because in the Eclipse debugger, it specifies unique IDs for each object.

I came up with a solution based on the fact that the "==" operator for objects only returns true if the two objects are actually the same instance.

import java.util.HashMap;
import java.util.Map;

/**
 *  Utility for assigning a unique ID to objects and fetching objects given
 *  a specified ID
 */
public class ObjectIDBank {

    /**Singleton instance*/
    private static ObjectIDBank instance;

    /**Counting value to ensure unique incrementing IDs*/
    private long nextId = 1;

    /** Map from ObjectEntry to the objects corresponding ID*/
    private Map<ObjectEntry, Long> ids = new HashMap<ObjectEntry, Long>();

    /** Map from assigned IDs to their corresponding objects */
    private Map<Long, Object> objects = new HashMap<Long, Object>();

    /**Private constructor to ensure it is only instantiated by the singleton pattern*/
    private ObjectIDBank(){}

    /**Fetches the singleton instance of ObjectIDBank */
    public static ObjectIDBank instance() {
        if(instance == null)
            instance = new ObjectIDBank();

        return instance;
    }

    /** Fetches a unique ID for the specified object. If this method is called multiple
     * times with the same object, it is guaranteed to return the same value. It is also guaranteed
     * to never return the same value for different object instances (until we run out of IDs that can
     * be represented by a long of course)
     * @param obj The object instance for which we want to fetch an ID
     * @return Non zero unique ID or 0 if obj == null
     */
    public long getId(Object obj) {

        if(obj == null)
            return 0;

        ObjectEntry objEntry = new ObjectEntry(obj);

        if(!ids.containsKey(objEntry)) {
            ids.put(objEntry, nextId);
            objects.put(nextId++, obj);
        }

        return ids.get(objEntry);
    }

    /**
     * Fetches the object that has been assigned the specified ID, or null if no object is
     * assigned the given id
     * @param id Id of the object
     * @return The corresponding object or null
     */
    public Object getObject(long id) {
        return objects.get(id);
    }


    /**
     * Wrapper around an Object used as the key for the ids map. The wrapper is needed to
     * ensure that the equals method only returns true if the two objects are the same instance
     * and to ensure that the hash code is always the same for the same instance.
     */
    private class ObjectEntry {
        private Object obj;

        /** Instantiates an ObjectEntry wrapper around the specified object*/
        public ObjectEntry(Object obj) {
            this.obj = obj;
        }


        /** Returns true if and only if the objects contained in this wrapper and the other
         * wrapper are the exact same object (same instance, not just equivalent)*/
        @Override
        public boolean equals(Object other) {
            return obj == ((ObjectEntry)other).obj;
        }


        /**
         * Returns the contained object's identityHashCode. Note that identityHashCode values
         * are not guaranteed to be unique from object to object, but the hash code is guaranteed to
         * not change over time for a given instance of an Object.
         */
        @Override
        public int hashCode() {
            return System.identityHashCode(obj);
        }
    }
}

I believe that this should ensure unique IDs throughout the lifetime of the program. Note, however, that you probably don't want to use this in a production application because it maintains references to all of the objects for which you generate IDs. This means that any objects for which you create an ID will never be garbage collected.

Since I'm using this for debug purposes, I'm not too concerned with the memory being freed.

You could modify this to allow clearing Objects or removing individual objects if freeing memory is a concern.

NateW
  • 568
  • 3
  • 22
0

Just to augment the other answers from a different angle.

If you want to reuse hashcode(s) from 'above' and derive new ones using your class' immutatable state, then a call to super will work. While this may/may not cascade all the way up to Object (i.e. some ancestor may not call super), it will allow you to derive hashcodes by reuse.

@Override
public int hashCode() {
    int ancestorHash = super.hashCode();
    // now derive new hash from ancestorHash plus immutable instance vars (id fields)
}
Glen Best
  • 21,413
  • 2
  • 52
  • 72
0

There is a difference between hashCode() and identityHashCode() returns. It is possible that for two unequal (tested with ==) objects o1, o2 hashCode() can be the same. See the example below how this is true.

class SeeDifferences
{
    public static void main(String[] args)
    {
        String s1 = "stackoverflow";
        String s2 = new String("stackoverflow");
        String s3 = "stackoverflow";
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());
        System.out.println(System.identityHashCode(s1));
        System.out.println(System.identityHashCode(s2));
        System.out.println(System.identityHashCode(s3));
        if (s1 == s2)
        {
            System.out.println("s1 and s2 equal");
        } 
        else
        {
            System.out.println("s1 and s2 not equal");
        }
        if (s1 == s3)
        {
            System.out.println("s1 and s3 equal");
        }
        else
        {
            System.out.println("s1 and s3 not equal");
        }
    }
}