Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Getting a unique hash value of an object

Tags:

java

I am trying to get a unique hash value for a Java object, such as the following are true:

  1. If A == B then A.HashValue() == B.Hash.HashValue()
  2. If A != B then A.HashValue() != B.HashValue()

Lets say the object contains several boolean and integer fields.

like image 823
Gjorgji Avatar asked Feb 15 '11 05:02

Gjorgji


2 Answers

// Very important edit...

Gjorgji, I know you accepted the answer below as correct, but I have found it to be incorrect.

If you have a class like this:

class tiny {
    int a;
    public int hashCode() { return a; }
}

You have already maxed out all possible hash codes. (If this isn't clear why, please say so.)

So, if you add ANY more information to the object, if you want that information represented in the hashCode, you're going to have a collision somewhere.

But, for that matter, you don't really want to set out to get a hashCode that's 100% unique to an object. That's really not the point of hashCode!

The point of hashCode is to give you a "unique enough" identifier to the object so you can place it in a hash bucket. It's not for identification so much as it is for classification. The idea is if you have a whole bunch of objects, you're probably not going to have many collisions, so you are probably going to have pretty fast access to what you're looking for if you grouped items by their hashCode.

If this means you deselect my answer as correct, that's okay. It really isn't correct for what you're looking for. My hope is that you realize this explanation of hashCode leads you to the correct usage, thereby keeping the correctness. But as Mark clearly pointed out, this doesn't actually solve the issue you stated.

Below is the old answer:

===========================================================

A good article on it is found here, from Effective Java (hands down the best "I want to learn how to be a good Java developer" book out there.)

http://www.linuxtopia.org/online_books/programming_books/thinking_in_java/TIJ313_029.htm

class Gjorgji {
    boolean a;
    boolean b;
    boolean c;
    int x;
    int y;

    // EDIT: I almost forgot a VERY important rule...
    // WHEN YOU OVERRIDE hashCode, OVERRIDE EQUALS (and vice versa)
    public int equals(Object o) {
        if(!(o instanceof Gjorgji) return false;
        Gjorgji g = (Gjorgji)o;
        return a == g.a && b == g.b && c == g.c && x == g.x && y == g.y;

    }

    public int hashCode() {
        int hash = x ^ y;
        hash *= a ? 31 : 17; // pick some small primes
        hash *= b ? 13 : 19;
        hash *= c ? 11 : 29;
        return hash;
    }

}
like image 81
corsiKa Avatar answered Oct 01 '22 01:10

corsiKa


This is not possible in general, you must guarantee that if a.equals(b), then a.hashCode() == b.hashCode(). You cannot guarantee the reverse: you can always have collisions because the hashCode method only has a 32bit space and your JVM can have a 64bit space for identity hashcodes.

like image 28
sjr Avatar answered Oct 01 '22 02:10

sjr