0

I have a domain Class named Subscriber and its definition is something like this:

public class Subscriber {
   private long id;
   private String email;
   private String subscriberName;
   private Topic subscribingTopic;

   //other attributes and getters setters.
}

public class Topic{
   private long id;
   private String topicName; //unique
}

My problem is I need to override the equal() and hashCode() methods of this Subscriber class. Overriding equal() is somewhat easy task (just comparing basic attributes, in this case there are three of them). But I am facing problems while overriding hashCode() method. How I can write hashCode() that I can trust to be used by hibernate safely, while managing my domains. Can I trust IDE generated one?

Any help will be appreciated and thanks in advance!

Sazzadur Rahaman
  • 6,938
  • 1
  • 30
  • 52

4 Answers4

6

If you're on Java 7, you could use Objects.hash():

return Objects.hash(email, subscriberName, subscribingTopic);

If you're on Java 6, you could use Guava's Objects.hashCode() method (the same way as above).

If you're on Java 5, you could use Apache commons-lang HashCodeBuilder class to help you.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
4

You can use IDE like Eclipse to generate hashCode method for you. One sample hashCode method is below:

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((email == null) ? 0 : email.hashCode());
        result = prime * result + (int) (id ^ (id >>> 32));
        result = prime
                * result
                + ((subscriberName == null) ? 0 : subscriberName.hashCode());
        result = prime
                * result
                + ((subscribingTopic == null) ? 0 : subscribingTopic
                        .hashCode());
        return result;
    }

You need to create a similar hashCode method in Topic class as well.

Per Object#hashCode API:

The general contract of hashCode is:

Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

Its general practice to use prime number 31 and combine the attribute values in a*31^(x)+b*31^(x-1)+..c to achieve the unique number for the object. In the process, you can use the hashCode method of underline object. The above method also does the same.

Yogendra Singh
  • 33,927
  • 6
  • 63
  • 73
  • 2
    You should rather explain what should be kept in mind while generating or creating a `hashCode` method. Just giving away the code might solve the problem for this issue, but it does not really helps in long run. Please add some explanation. – Rohit Jain Nov 19 '12 at 16:45
2

How I can write hashCode() that returns unique hash value using the specified three attributes?

It does not have to be unique, only distinct enough to distinguish among non-equal values.

One common way is to use component hash codes, and combine them as ((h1*31)+h2)*31+h3 and so on.

Here is how you do it: first, define hashCode for the Topic, like this:

int hashCode() {
    return topicName.hashCode()*31 + (int)id;
}

You need to override Topic's equals as well!

Then define the hash code for Subscriber, like this:

int hashCode() {
    return id.hashCode()*31*31*31
         + email.hashCode()*31*31
         + subscriberName.hashCode()*31
         + subscribingTopic.hashCode();
}

The code above assumes that the constructor initializes all components of the Subscriber to be non-null.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • It probably doesn't matter terribly much, but I would be tempted to perform the multiplication (just by 31 or some other prime or near-prime number) AFTER adding each component, rather than multiplying by multiples of the multiplier. However, I also agree that in reality, the above will be perfectly adequate for the required purposes. – Neil Coffey Nov 19 '12 at 16:41
1

The hashCode() does not need to be unique. The only thing is that it must return the same hashcodes for obj1 and obj2, if obj1.equals(obj2). You can just return email.hashCode() for example.

Perfect hash function does not exist - it is not possible to return different hashcodes for every pair of different elements. Java uses equals for further differentiation(if the hashcodes are the same).

Petar Minchev
  • 46,889
  • 11
  • 103
  • 119