What is the contract between equals() and hashcode()? Learn how these methods work together when comparing objects in Java. Credit: Cagkan Sayin/Shutterstock 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() and hashcode() in Java? How to compare Java objects with equals() How to identify Java objects with hashcode() How to use equals() and hashcode() with collections You’ll also get: Guidelines for using equals() and hashcode() Rules for making object comparisons with equals() and hashcode() Mistakes to avoid when using equals() and hashcode() What to remember about equals() and hashcode() 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(new Simpson("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(new Object())); 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: HashSet TreeSet LinkedHashSet CopyOnWriteArraySet 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 the equals() method or vice versa. Not overriding equals() and hashcode() when using hash collections like HashSet. Returning a constant value in the hashcode() method instead of returning a unique code per object. Using == and equals interchangeably. The == compares Object references, whereas equals() compares object values. What to remember about equals() and hashcode() It’s a good practice to always override equals() and hashcode() methods in your POJOs. Use an effective algorithm to generate a unique hashcode. When overriding the equals() method, always override the hashcode() 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() and hashcode() 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. Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos