Overriding equals and hashCode in Java – J039
DeegeU Java Course
The “Overriding equals and hashCode in Java” video is part of a larger free online class called “Free Java Course Online”. You can find more information about this class on “Free Java Course Online” syllabus.
Transcript – Overriding equals and hashCode in Java
How can I tell if two Java instances represent the same instance? And what does class equality mean in Java? That’s next!
Growing up in the USA, I was fed a huge dose of Sesame Street on television. Sesame Street was a program that taught preschool kids simple lessons like shapes, letters and numbers. I think my parents saw the show as an hour of their day they could safely ignore me. In the show there was a segment where three kids were shown, and one was different in some way. They sang a song one of these kids is not like the others, and you’d have to figure it out before the song ended.
The question here is, what does it mean to be the same or different in Java. If you modeled me, maybe two of me had blue shirts and the third had a red shirt. So their shirt color attribute would be the blue for two DJ instances, and red for a third DJ instance. Are they equal because they have the same color shirt, or are they the same me? We’re going to clear that up in this lesson as we learn about what it means in Java for two instances to be equal.
public static void main(String args[]) { DJ a = new DJ(“blue”); if (a == a) { System.out.println(“A is equal to itself”); } }
Just with the DJ example, we can see that what equals means is a bit fuzzy. Let’s start with what we know. If we have an instance, any class, it’s equal to itself. That’s pretty obvious. A equals A.
public static void main(String args[]) { DJ a = new DJ(“blue”); AnyClass b = a; if (a == b) { System.out.println(“A is equal to B”); } }
Now if we create a second instance, call it B, and assign it the reference A. Well in this case we have two references pointing to the same instance. We saw this in the copy constructor tutorial. So in this case A equals B.
public static void main(String args[]) { DJ a = new DJ(“blue”); DJ b = new DJ(“blue”); if (a == b) { System.out.println(“A is equal to B”); } }
Here’s where things get fuzzy. Let’s create two DJ classes. They both have a shirt color, which is blue. If we compare the two in Java, they’re not equal. DJ A is not DJ B. They just have the same values. The reason is the equals operator tests for identity. Identity isn’t equality.
The String class is a bit trickier. If we create two strings, both with the same values, and then compare them. What happens. Java says they are equal. Since I know there are some of you out there screaming “not true”, so let’s run the code.
Two strings. We’ll set each to the same value, and then compare them using the equality operator. And it prints “very cool”. This pretty much breaks everything we’re learning here. Basically Java gets smart about strings, and does something called interning. We saw something similar to this when comparing small integer classes. We’ll cover strings in depth very soon.
So why did we do that? I wanted to show you that we really need to understand what we are doing when we compare instances. If we do the same test with two instances, each having a single attribute with the same value, the instances will fail the equality test. The equality operator isn’t the best choice for testing equality, because it has different results. So how do we test for equality?
Every Java class has a method called equals. It’s defined in the class Object. We call it on one instance, and pass it the second instance we want to test. Here’s the way we really want to test strings.
There’s a catch however. In the Object class, the equals method just calls the equals operator. This means we need to override the equals method to define what equals means for our classes.
@Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (obj instanceof DJ) { DJ test = (DJ) obj; if (test.myShirtColor == this.myShirtColor) { return true; } } return false; }
If we override equals, here’s what we need to keep in mind. First an instance must be equal to itself. Any test we write must first check to see if the two instances are really the first instance.
Next we check to see if the parameter instance is null. If it’s null we must return false. This makes sense, because the equals instance exists. Null doesn’t exist. So they can’t be equal.
Third we make sure we have two instances from the same class. We’re getting an Object instance as the parameter when we call equals, so we don’t know until we check. Or cast it…
Which is what we do next. We’ll cast the instance to the class we’re testing.
Finally, we check every attribute. If the attribute is another class, you have to make the decision again if equals needs to be overridden. If everything passes, we have two equal instances. Otherwise we return false.
And just when we thought we were done, we have another method to override – hashcode. This method is used in hash maps. We haven’t covered hashmaps classes yet, but here’s a cliff note version of what is happening. Hashmaps have several buckets where we can store instances. hashcode produces an integer which is the bucket number we store our class. This makes it much easier to find them later when you have millions of instances.
If we don’t override hashcode, two instances that evaluate to equal would have different hashcodes. If we use our instance as the key for a hashmap, we will run into a problem where two instances which evaluate to equal will be stored with different values. That’s bad.
Let’s implement hashcode. The two rules are, first two equal instance always result in the same hashcode.
Second, if two instances have the same hashcode, that says nothing about if the two are equal. It could be some weird quirk that two unequal instances return the same bucket number. The idea isn’t to give unique buckets for each class, we want to make sure each bucket has roughly an equal number of items in it.
@Override public int hashCode() { int hash = 7; hash = 31 * hash + Objects.hashCode(this.myShirtColor); return hash; }
When we calculate a hashcode, we want to first start with a prime non-zero number. That’s our initial hash.
Then for every attribute in our class that contributes to equality, we need to combine with our initial hash. So using this chart, calculate the value. Once we have a number, we take our initial hash multiplied with another non-zero prime number, and add the calculated value.
After we’ve done this for every attribute in our class, we return the result.
That’s alot of work. A better way is to rely on our IDE to generate this. For example, we can go into our class in Netbeans, right click and select insert code. From there select equals and hashcode. That will do this for you. It’s still important to know what the IDE is doing for us, because you’ll always want to double check the IDE didn’t do anything stupid.
Wow. That was a long tutorial. Thank you for making it to the end!
Equality is something that should be easy but it has many nuances, so if you have any questions let me know in the comments. Make sure you subscribe to the channel, so you don’t miss a video! Liking the video helps me understand what I’m doing right, so if you liked the video… you know what to do.
And with that, I’ll see you in the next tutorial!
<!-- DeegeU - Right Side -->
<ins class="adsbygoogle" style="display:inline-block;width:336px;height:280px" data-ad-client="ca-pub-5305511207032009" data-ad-slot="5596823779"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></p>
Tools Used
- Java
- NetBeans
Media Credits
All media created and owned by DJ Spiess unless listed below.
- No infringement intended
Cold Funk – Funkorama by Kevin MacLeod is licensed under a Creative Commons Attribution license (https://creativecommons.org/licenses/by/4.0/)
Source: http://incompetech.com/music/royalty-free/index.html?isrc=USUAN1100499
Artist: http://incompetech.com/
Get the code
The source code for “Overriding equals and hashCode in Java” can be found on Github. If you have Git installed on your system, you can clone the repository by issuing the following command:
git clone https://github.com/deege/deegeu-java-intro.git
Go to the Support > Getting the Code page for more help.
If you find any errors in the code, feel free to let me know or issue a pull request in Git.
Don’t miss another video!
New videos come out every week. Make sure you subscribe!
Comments
DJ Spiess
Your personal instructor
My name is DJ Spiess and I’m a developer with a Masters degree in Computer Science working in Colorado, USA. I primarily work with Java server applications. I started programming as a kid in the 1980s, and I’ve programmed professionally since 1996. My main focus are REST APIs, large-scale data, and mobile development. The last six years I’ve worked on large National Science Foundation projects. You can read more about my development experience on my LinkedIn account.