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.
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.
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.
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.
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.
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!