What is the contract between equals() and hashcode()? Learn how these methods work together when comparing objects in Java.
Java’s equals()
and hashcode()
are two methods that work together to verify if two objects have the same value. You can use them to make object comparisons easy and efficient in your Java programs.
Java equals() and hashcode()
In this article, you’ll learn:
- Why override
equals()
andhashcode()
in Java? - How to compare Java objects with
equals()
- How to identify Java objects with
hashcode()
- How to use
equals()
andhashcode()
with collections
You’ll also get:
- Guidelines for using
equals()
andhashcode()
- Rules for making object comparisons with
equals()
andhashcode()
- Mistakes to avoid when using
equals()
andhashcode()
- What to remember about
equals()
andhashcode()
Why override equals() and hashcode() in Java?
Method overriding is a technique where the behavior of the parent class or interface is written again (overridden) in the subclass in order to take advantage of Polymorphism. Every Object
in Java includes an equals()
and a hashcode()
method, but they must be overridden to work properly.
To understand how overriding works with equals()
and hashcode()
, we can study their implementation in the core Java classes. Below is the equals()
method in the Object
class. The method is checking whether the current instance is the same as the previously passed Object
.
public boolean equals(Object obj) {
return (this == obj);
}
When the hashcode()
method is not overridden, the default method in the Object
class will be invoked. This is a native method, which means it will be executed in another language like C, and will return some code regarding the object’s memory address. (It’s not that important to know exactly how this method works unless you are writing JDK code.)
@HotSpotIntrinsicCandidate
public native int hashCode();
When the equals()
and hashcode()
methods are not overridden, you will see the above methods invoked instead. In this case, the methods do not fulfill the real purpose of equals()
and hashcode()
, which is to check whether two or more objects have the same values.
As a rule, when you override equals()
you must also override hashcode()
.
How to compare Java objects with equals()
We use the equals()
method to compare objects in Java. To determine if two objects are the same, equals()
compares the values of the objects’ attributes:
public class EqualsAndHashCodeExample {
public static void main(String... equalsExplanation) {
System.out.println(new Simpson("Homer", 35, 120)
.equals(new Simpson("Homer",35,120)));
System.out.println(new Simpson("Bart", 10, 120)
.equals(new Simpson("El Barto", 10, 45)));
System.out.println(new Simpson("Lisa", 54, 60)
.equals(new Object()));
}
static class Simpson {
private String name;
private int age;
private int weight;
public Simpson(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Simpson simpson = (Simpson) o;
return age == simpson.age &&
weight == simpson.weight &&
name.equals(simpson.name);
}
}
}
In the first comparison, equals()
compares the current object instance with the object that was passed. If the two objects have the same values, equals()
returns true
.
In the second comparison, equals()
checks to see whether the passed object is null, or if it’s typed as a different class. If it’s a different class then the objects are not equal.
Finally, equals()
compares the objects’ fields. If two objects have the same field values, then the objects are the same.
Object comparisons
Now, let’s view the results of these comparisons in our main()
method. First, we compare two Simpson
objects:
System.out.println(new Simpson("Homer", 35, 120).equals(new Simpson("Homer", 35, 120)));
The objects here are identical, so the result will be true
.
Next, we compare two Simpson
objects again:
System.out.println(new <code>Simpson
("Bart", 10, 45).equals(newSimpson
("El Barto", 10, 45)));
The objects here are nearly identical but their names are different: Bart and El Barto. Therefore the result will be false
.
Finally, let’s compare a Simpson
object and an instance of the class Object:
System.out.println(new <code>Simpson
("Lisa", 54, 60).equals(newObject
()));
In this case the result will be false
because the class types are different.
equals() is not the same as ==
At first glance, the ==
operator and equals()
method may appear to do the same thing, but they work differently. The ==
operator compares whether two object references point to the same object. For example:
System.out.println(homer == homer2);
In the first comparison, we instantiated two different Simpson
instances using the new
operator. Because of this, the variables homer
and homer2
will point to different Object
references in the memory heap. So we’ll have false
as the result.
System.out.println(homer.equals(homer2));
In the second comparison, we override the equals()
method. In this case only the names are compared. Because the name of both Simpson
objects is “Homer” the result is true
.
How to identify Java objects with hashcode()
We use the hashcode()
method to optimize performance when comparing objects. Executing hashcode()
returns a unique ID for each object in your program, which makes the task of comparing the whole state of the object much easier.
If an object’s hashcode is not the same as another object’s hashcode, there is no reason to execute the equals()
method: you just know the two objects are not the same. On the other hand, if the hashcode is the same, then you must execute the equals()
method to determine whether the values and fields are the same.
Here’s a practical example with hashcode()
.
public class HashcodeConcept {
public static void main(String... hashcodeExample) {
Simpson homer = new Simpson(1, "Homer");
Simpson bart = new Simpson(2, "Homer");
boolean isHashcodeEquals = homer.hashCode() == bart.hashCode();
if (isHashcodeEquals) {
System.out.println("Should compare with equals method too.");
} else {
System.out.println("Should not compare with equals method because " +
"the id is different, that means the objects are not equals for sure.");
}
}
static class Simpson {
int id;
String name;
public Simpson(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Simpson simpson = (Simpson) o;
return id == simpson.id &&
name.equals(simpson.name);
}
@Override
public int hashCode() {
return id;
}
}
}
A hashcode()
that always returns the same value is valid but not very effective. In this case the comparison will always return true
, so the equals()
method will always be executed. There is no performance improvement in this case.
Using equals() and hashcode() with Java collections
The Set
interface is responsible for ensuring no duplicate elements are inserted in a Set
subclass. The following are some of the classes that implement the Set
interface:
Only unique elements may be inserted into a Set
, so if you want to add an element to the HashSet
class (for example), you must first use the equals()
and hashcode()
methods to verify the element is unique. If the equals()
and hashcode()
methods weren’t overridden in this case, you would risk inserting duplicate elements in the code.
In the code below, we’re using the add
method to add a new element to a HashSet
object. Before the new element is added, HashSet
checks to see whether the element already exists in the given collection:
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
If the object is the same, the new element won’t be inserted.
Guidelines for using equals() and hashcode()
You should only execute an equals()
method for objects that have the same unique hashcode ID. You should not execute equals()
when the hashcode ID is different.
This principle is mainly used in Set
or Hash
collections for performance reasons.
Object comparison with equals() and hashcode()
When a hashcode()
comparison returns false
, the equals()
method must also return false. If the hashcode is different, then the objects definitely are not equal.
When the equals()
method returns true
, it means that the objects are equal in all values and attributes. In this case, the hashcode comparison must be true as well.
Take the equals() and hashcode() challenge!
It’s time to test your skills with equals()
and hashcode()
. Your goal in this challenge is to figure out the output of the two equals()
method comparisons and guess the size of the Set
collection.
To start, study the following code carefully:
public class EqualsHashCodeChallenge {
public static void main(String... doYourBest) {
System.out.println(new Simpson("Bart").equals(new Simpson("Bart")));
Simpson overriddenHomer = new Simpson("Homer") {
public int hashCode() {
return (43 + 777) + 1;
}
};
System.out.println(new Simpson("Homer").equals(overriddenHomer));
Set set = new HashSet(Set.of(new Simpson("Homer"), new Simpson("Marge")));
set.add(new Simpson("Homer"));
set.add(overriddenHomer);
System.out.println(set.size());
}
static class Simpson {
String name;
Simpson(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
Simpson otherSimpson = (Simpson) obj;
return this.name.equals(otherSimpson.name) &&
this.hashCode() == otherSimpson.hashCode();
}
@Override
public int hashCode() {
return (43 + 777);
}
}
}
Remember, analyze the code first, guess the result, then run the code. Your goal is to improve your skill with code analysis and absorb core Java concepts to make your code more powerful. Choose your answer before checking the correct one below.
A)
true
true
4
B)
true
false
3
C)
true
false
2
D)
false
true
3
Solving the equals() and hashcode() challenge
In the first equals()
method comparison, the result is true
because the state of the object is exactly the same and the hashcode()
method returns the same value for both objects.
In the second equals()
method comparison, the hashcode()
method is being overridden for the overridenHomer
variable. The name is “Homer” for both Simpson
objects, but the hashcode()
method returns a different value for overriddenHomer
. In this case, the final result from the the equals()
method will be false
because the method contains a comparison with the hashcode.
You might notice that the size of the collection is set to hold three Simpson
objects. Let’s check this in a detailed way.
The first object in the set will be will be inserted normally:
new Simpson("Homer");
The next object will be inserted normally, as well, because it holds a different value from the previous object:
new Simpson("Marge");
Finally, the following Simpson
object has the same value as the first object. In this case the object won’t be inserted:
set.add(new Simpson("Homer"));
As we know, the overridenHomer
object uses a different hashcode value from the normal Simpson(“Homer”)
instantiation. For this reason, this element will be inserted into the collection:
overriddenHomer;
Answer key
The answer is B. The output would be:
true
false
3
Mistakes to avoid with equals() and hashcode()
- Forgetting to override
hashcode()
along with theequals()
method or vice versa. - Not overriding
equals()
andhashcode()
when using hash collections likeHashSet
. - Returning a constant value in the
hashcode()
method instead of returning a unique code per object. - Using
==
andequals
interchangeably. The==
comparesObject
references, whereasequals()
compares object values.
What to remember about equals() and hashcode()
- It’s a good practice to always override
equals()
andhashcode()
methods in your POJOs. - Use an effective algorithm to generate a unique hashcode.
- When overriding the
equals()
method, always override thehashcode()
method as well. - The
equals()
method should compare the whole state of objects: values from fields. - The
hashcode()
method could be the ID of a POJO. - When the result of comparing two object’s hashcodes is false, the
equals()
method should also be false. - If
equals()
andhashcode()
are not overridden when using hash collections, the collection will have duplicate elements.
Video challenge! Debugging equals() and hashcode()
Debugging is one of the easiest ways to fully absorb programming concepts while also improving your code. In this video you can follow along while I debug and explain the Java equals()
and hashcode()
challenge.
Learn more about Java
- Get more quick code tips: Read all of Rafael’s articles in the InfoWorld Java Challengers series.
- Check out the videos in Rafael’s Java Challengers video playlist.
- Find even more Java Challengers on Rafael’s Java Challengers blog and in his book, with more than 70 code challenges.