Equals and hashcode methods are two primaries but yet one of the most important methods for java developers to be aware of. Java intends to provide equals and hashcode for every class to test equality and to provide a hash or digest based on the content of the class. The importance of hashcode increases when we use the object in different collection classes which works on hashing principle e.g. hashtable and hashmap. A well-written hashcode method can improve performance drastically by distributing objects uniformly and avoiding a collision.
In this article, we will see how to correctly override the hashcode() method in java with a simple example.
We will also examine the important aspects of hashcode contracts in java. This is in continuation of my earlier post on overriding the equals method in Java, if you haven’t read it already I would suggest going through it.
In this article, we will see how to correctly override the hashcode() method in java with a simple example.
We will also examine the important aspects of hashcode contracts in java. This is in continuation of my earlier post on overriding the equals method in Java, if you haven’t read it already I would suggest going through it.
General Contracts for hashCode() in Java
1) If two objects are equal by the equals() method then their hashcode returned by the hashCode() method must be the same.
2) Whenever the hashCode() method is invoked on the same object more than once within a single execution of the application, hashCode() must return the same integer provided no information or fields used in equals and hashcode is modified. This integer is not required to be the same during multiple executions of application though.
3) If two objects are not equaled by the equals() method it is not required that their hashcode must be different. Though it’s always good practice to return different hashCode for unequal object. Different hashCode for a distinct objects can improve the performance of hashmap or hashtable by reducing collision.
To better understand concept of equals and hashcode and what happens if you don’t override them properly I would recommend understanding of How HashMap works in Java
Overriding hashCode method in Java
We will follow step by step approach for overriding hashCode method. This will enable us to understand the concept and process better.
1) Take a prime hash e.g. 5, 7, 17 or 31 (prime number as hash, results in distinct hashcode for distinct object)
2) Take another prime as multiplier different than hash is good.
3) Compute hashcode for each member and add them into final hash. Repeat this for all members which participated in equals.
4) Return hash
Here is an example of hashCode() method
@Override
public int hashCode() {
int hash = 5;
hash = 89 hash + (this.name != null ? this.name.hashCode() : 0);
hash = 89 hash + (int) (this.id ^ (this.id >>> 32));
hash = 89 hash + this.age;
return hash;
}
It’s always good to check null before calling hashCode() method on members or fields to avoid NullPointerException, if member is null than return zero. Different data types has different way to compute hashCode.Integer members are simplest we just add there value into hash, for other numeric data-type are converted into int and then added into hash. Joshua bloach has full tables on this. I mostly relied on IDE for this.
Better way to override equals and hashCode
Let’s see how we can override the hashcode method in Netbeans and Eclipse.
In Netbeans
1) Write your Class.
2) Right click + insert code + Generate equals() and hashCode().
In Eclipse
1) Write to your Class.
2) Go to Source Menu + Generate hashCode() and equals()
Things to remember while overriding hashcode in Java
1. Whenever you override the equals method, hashcode should be overridden to be in compliance with equals hashcode contract.
2. hashCode() is declared in Object class and return type of hashcode method is int and not long.
3. For an immutable object, you can cache the hashcode once generated for improved performance.
4. Test your hashcode method for equals hashcode compliance.
5. If you don't override hashCode() method properly your Object may not function correctly on hash-based collection e.g. HashMap, Hashtable or HashSet.
A complete example of equals and hashCode
public class Stock {
private String symbol;
private String exchange;
private long lotSize;
private int tickSize;
private boolean isRestricted;
private Date settlementDate;
private BigDecimal price;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((exchange == null) ? 0 : exchange.hashCode());
result = prime * result + (isRestricted ? 1231 : 1237);
result = prime * result + (int) (lotSize ^ (lotSize >>> 32));
result = prime * result + ((price == null) ? 0 : price.hashCode());
result = prime * result
+ ((settlementDate == null) ? 0 : settlementDate.hashCode());
result = prime * result + ((symbol == null) ? 0 : symbol.hashCode());
result = prime * result + tickSize;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || this.getClass() != obj.getClass()){
return false;
}
Stock other = (Stock) obj;
return
this.tickSize == other.tickSize && this.lotSize == other.lotSize &&
this.isRestricted == other.isRestricted &&
(this.symbol == other.symbol|| (this.symbol != null && this.symbol.equals(other.symbol)))&&
(this.exchange == other.exchange|| (this.exchange != null && this.exchange.equals(other.exchange))) &&
(this.settlementDate == other.settlementDate|| (this.settlementDate != null && this.settlementDate.equals(other.settlementDate))) &&
(this.price == other.price|| (this.price != null && this.price.equals(other.price)));
}
}
Writing equals and hashcode using Apache Commons EqualsBuilder and HashCodeBuilder
EqualsBuilder and HashCodeBuilder from Apache commons are a much better way to override equals and hashcode method, at least much better than ugly equals, hashcode generated by Eclipse. I have written the same example by using HashCodebuilder and EqualsBuilder and now you can see how clear and concise they are.
@Override
public boolean equals(Object obj){
if (obj instanceof Stock) {
Stock other = (Stock) obj;
EqualsBuilder builder = new EqualsBuilder();
builder.append(this.symbol, other.symbol);
builder.append(this.exchange, other.exchange);
builder.append(this.lotSize, other.lotSize);
builder.append(this.tickSize, other.tickSize);
builder.append(this.isRestricted, other.isRestricted);
builder.append(this.settlementDate, other.settlementDate);
builder.append(this.price, other.price);
return builder.isEquals();
}
return false;
}
@Override
public int hashCode(){
HashCodeBuilder builder = new HashCodeBuilder();
builder.append(symbol);
builder.append(exchange);
builder.append(lotSize);
builder.append(tickSize);
builder.append(isRestricted);
builder.append(settlementDate);
builder.append(price);
return builder.toHashCode();
}
public static void main(String args[]){
Stock sony = new Stock("6758.T", "Tkyo Stock Exchange", 1000, 10, false, new Date(), BigDecimal.valueOf(2200));
Stock sony2 = new Stock("6758.T", "Tokyo Stock Exchange", 1000, 10, false, new Date(), BigDecimal.valueOf(2200));
System.out.println("Equals result: " + sony.equals(sony2));
System.out.println("HashCode result: " + (sony.hashCode()== sony2.hashCode()));
}
The only thing to concern is that it adds a dependency on the apache-commons jar, most people use it but if you are not using then you need to include it for the writing equals and hashcode method.
Related Java tutorials
Excellent tips. But I would like to say that JDK7 has come up with awesome Objects class which can easily generate hashcodes for classes.
ReplyDeleteHow hashcode behaves in String
@OnlySoftware , thanks for your suggestion I tried both EqualsBuilder and HashCodeBuilder and found them easy to use and probably best option, though it introduce additional dependency on Apache commons but in the end its worth to include Apache commons which has lots of utility.
ReplyDeleteCan we make hashCode method synchronized in Java, What are the consequences of using synchronized keyword with equals and hashCode method ? Also is there any way we can still do in memory comparison using native equals method in Java
ReplyDeletehashcode in java example is very good but you didn't tell us how to write hashcode for immutable class, will be same of there would be any difference. also what are performance consideration in java while overriding hashcode in java ? What happend if I return same hashcode for every object ?
ReplyDeleteUse IDE to generate code for equals and hashCode, there is no point doing it manually. you might want to highlight the importance of hashCode when an object is used as key in HashMap. Though its not a requirement that unequal object should have unequal or unique hashCode, you should try for that.
ReplyDelete@javin am not getting auto-generate hashcode and equals option in netbeans 7.2.
ReplyDeletehelp pleas??
I get an exception when I’m trying to start tomcat (in thread main java.lang.NoClassDefFoundError:
ReplyDeleteWhy do you need hashcode? I mean what is the practical application of it's?
ReplyDeleteOverriding equals() and hashcode()..!!? How/why would you use that?!
Please be specific.
Hi,
ReplyDeletethis is an amazing article...
It will be great to know more about the has code as in why we need a hash code at all.. how a hash code is used by jvm ?
hash code comes into picture when there is a collision, but I am not sure if that is it, the use of hash code.
Thanks in advance
Naveen Vanjani
Hi Nice article,
ReplyDeleteIn one of my interviews asked me a question that what happens when hashcode of two key objects are equals? tell me what happens while put and get methods. I couldn't answer this question. I came back and written a simple program like for all custom objects it returns the same hashcode, tried adding them to hashmap. But it is working fine, I mean to say I could see the size of the hashmap correctly though I gave same hashcode. Also I could get the values properly, I dont see any issues. I printed the hashcode for all the objects they are same only. So finally how will I know hash collision happened?
@Naveen Vanjani and saikinranputta
ReplyDeleteYou need to override equals and hashcode if you want colletions based on hashes to work well, like hashset and hashmap.
If you put a Person object with the same 'name' and 'surname' fields inside a HashSet many times you'd expect the set to only have it once, but as their hashcodes wouldn't be the same without overriding hashcode() you'd have it repeated.
And equals is needed because sometimes in HashMaps for example there are hashcode collisions, and when that happens the objects are put in the same bucket (linkedlist). Then to look for the right object the equals method is used.
@Venkat Sarma
ReplyDeleteProbably you did override hashcode() without overriding equals. So in that case all your objects were stored in the same bucket, which leads to O(n) lookup instead of O(1) which is normally expected in a HashMap.
Hello Javin, What is the purpose of hashCode and what is the relationship between equals and hashCode in Java, does compiler complains if we override one but not other? if not, why not?
ReplyDeleteHello Gauri,, No, compiler will not give any error. If two objects are equal using equals() method then their hashCode() methods also should return same integer value. Vice versa is not true.
ReplyDelete