so continuing on now with our heavenly body code and hash sets specifically I just
want to point out that the Java documentation does warn you that if
you're using your own objects as either a key in a map or as an element in the
set that you should override the equals and hash Code methods so what I'm going to do is
show you how to do that but before we start doing that I'm going to show you what
happens if we don't actually override them and the problem you get yourself into so what I'm going to do is
go back to our main class and I'm going to talk about creating a new pluto object
and we are going to add it to the project set as the same way as we have done before so we gonna
type..and we are going to make the orbital period 842...
now the point I want to make here is the original one line 73
the orbital period was 248 so were adding another one here
with a different orbital period so we going to...and you'd think
that all things being equal we got the same name for pluto so that we established in the previous
video that sets are unique and you can only have 1 item the same in a set so if
we then put this code in type some code in to go through the list of planets lets see
what happens
so I'm going to type...
...so let's actually just run this now
so as you can see pluto is shown as twice now depending on your operating system
and version of Java because sets aren't necessarily in order you might have to you may
not get them appearing straight after each other like they are there because you can see the other
things aren't ordered in a to z basically the bottom line here is that there is problem isn't there
that pluto is now appearing twice now I didn't choose that to make it feel better
because it's no longer a planet
we would get the same result no matter which body we used so again the I made a point out the fact that a set
cannot contain duplicates so how come a face value we got a duplicate well the
reason is the two java objects do not compare equal so the set is happy to accept
both of them for that reason and if we use them as keys in a map same thing will happen as well
and we will have two entries in a map so this is why the equals method has to be
overwritten our heavenly body class now the reason that they don't compare equal is
because the base object class from which all other classes are derived just defines
a very simple equals method that performs what is known as referential
equality and both references point to the same object then their equal otherwise
they are not that's the default equals that comes with the base object class and of
course all Java classes inherit from
so that's to say that it just uses equals to equal to perform a comparison and this is exactly
the same as comparing two strings using equals equals something
that hopefully I've told you not to do that so the string classes is overridden
the equals method so that when we use is for comparing strings it works as we expected if we looked
at the source code for that you would see that was the case so what we can do is we can go
back to our heavenly body and make some changes but before we do that what I
want to do is just show you how this works by using an object so right at the
bottom of here where we typed in our main method in for our main class we can type...
....object is the one that's built into Java the base object that all other
objects inherit from...
...and the reason I'm doing that so we can actually check the code so we
can go into the code and see what it's doing so I can click on equals click that
we can see the code and you can see the base object code their standard
equals method is the object this current object is equal equal to whatever is passed as a parameter
so you can see that's very very basic referential equality which isn't
generally what we want it's basically saying both references point to the same object
then they are equal otherwise they are not so that is by default in the object class itself but we have a
look at the equals for string and because we put a string there at the start we are going
to call string we can click on that and have a look at it and you can see we got a different set of equals so
its pretty clear that the string class which again inherits from the object
class has overwritten equals method and that's the code they are using to actually
do a comparison from one string to another and I think I've said this in a number of times but that is control click so
you can hold down CTRL on Windows or Linux machine on a Mac its command and
then click it and you can get into and see the source code so just getting back to
the String class again there is actually some good code to look at it so
probably a good starting point is certainly more complicated but its a
good starting point good example for how to write an equals method so the string equals
method itself performs a useful optimization first by checking for
string is being compared to itself
you can see that on line 165 obviously it returns true if that's the case and
skips any subsequent checking and you can imagine that an object that's used so
much in Java code it really would need to be optimized as much as possible
because virtually every program you write there's a high likelihood you'll be
using string in a few places so the Java creators that people that created Java
language and enhance it and update it obviously worked on this optimization
after that on line 65 after it returns true if it was the same object
what it does is it checks that the object being compared is a string so its using instance of string which is
a way of checking that a particular object
is a string as you can see on line 64 the parameter that was passed to the
equals method is of type object so it's determining now on line 68 whether the
object is a string that we comparing it because in this case there is no point
going any further if it is not a string essentially you can see it will dropout and
ultimately return false on line 83 if it wasn't a string so this code from line
63 onwards to line 80 is only going to be executed if it is a string but in our example when
we're dealing with our own class you need to be careful here thinking about it if
our heavenly body class is a sub class instance of a return true when an object
of the subclass type is used here so we need to look at an alternative checked
to perform when we implement equals for our heavenly body class and you can see the rest of the
method pretty straightforward as you can see it first checks that the links are
equal then it checks each character with a corresponding character in the other
string for equality and the method returns false if any don't match
and returns true of course it gets right down to here and everything has matched and
basically the same length and the same number of characters have been shown to
be the case in entire strings so unfortunately overriding equals is not
really straightforward so if two objects can compare equal then their hash codes
must also be the same which is why you must override the hash code method if you ever
override equals
so in case it wasn't clear enough on that lecture I'm going to explain again hash
collections towards objects so I'm going to bring this image on the screen so you can see so the essence of this is
that when storing objects in a hashed collections such as hash sets or hash
map think if the collection is having a number of buckets to store the objects in you can
see that represented in the graphics on the screen now the hash code determines
which bucket and objects gonna go into now there is a requirement that any objects that are
equal should always had the same hash code and ultimately so that they will
end up in the same bucket but the opposite is not required so two objects
that are equal do not have to have different hash codes in the diagram
object one goes into bucket one
object two goes into bucket two and so on now object five has the same has code as object
four so goes to the same bucket which is bucket four and object 6 generates the
same hash code as object two so that goes into the same bucket as object two so when we add
an object it's hash Code tells the collection which bucket it should go into now they may
already be objects in that bucket so each is compared to the new object to
make sure that it's not already in there now because the comparison is performed
using the equals method the collection will only know if it's already there if it's
looking in the right bucket so the hash code must be
the same
and equals returns true now it is now use for equals returning true if the collection is
checking the wrong bucket that is if the hash code for the new object is not the
same as an object that is that it's equal too
if we try to add another object that is equal too object say 6 number then the
hash code indicate that bucket 2 is the one to check the collection class will check all the
objects in bucket 2 went it finds object 6 this will compare equal to the new
object so that the new object is then not added to the collection but on the
other hand if our new object breaks the rules and has a different hash code to
object 6 even though it compares equal to it that's the important thing then the
collection will be looking in the wrong bucket and ultimately will not find it
so the new object will then be added to the collection and at that point we'll
get a duplicate but it can even get worse than that so if we don't iterate over the
collection trying to find that new object so that we can remove it
we may well get to the old objects 6 first and not the new ones so our code will check if
the object we just pulled from the collection is the same as the one we
want to remove and of course equals will return true so we remove the object
from the collection but actually remove the original not the duplicate so we
probably wouldn't iterate over the collection we already have a reference
to the object we wanted to remove but you can see that it's quite easy or hopefully it is
easy for you to see the potential for error in this scenario so there has to
be a strict relationship between hash Code and equals so two objects compare equal
then they must have the same hash code so I hope that's made it clear so the
bottom line with all this waffle that I've just talked about is that if 2 objects compare
equal they must have the same hash code that's really the bottom line so it's now time to
override the equals and hash Code methods in our heavenly body class and will do first is
will start by defining what we mean by equals so gonna bring up the heavenly body
class so in this case for our particular class this is pretty easy to decide
because astronomical objects are named well two heavenly bodies have the same
are the same if they have the same name but if we're dealing with people we
may have to consider additional fields because many people of course can share
the same so that case we may also have a check of the date of birth Social
Security number or other information that can be used to uniquely identify a person so
here's a first candidate for the equals method in heavenly body let us see if we can
actually start of so I'm gonna come down here now what we could do is I could override
this come down here and notice how its got equals and hash code so intelliJ is also clearly aware
here that the equals and hash Code are hand in hand but if I start clicking on that I
get something pretty unique I actually get a wizard and I can go through and I can select fields
and I'm not going to do that now I'm gonna go through just
typed it in manually but this is just another way to create the equals and hash Code
automatically and that is a feature of intelliJ but it's actually a better
value for us at the moment if we do this manually so going to back up here and I'm
going to do @override I'm gonna type this manually...
...first of all we're going to do that first check to see whether we're dealing
with the same object remember we used the equals equals you saw that in the
String class and obviously also in the object class we are going to put...
...if that is the case then really we don't need to do any more processing so we return
true because we established that this is the same object so doesn't object equal itself
yes it does so at that point we are going to return true so what we are doing now is will print out
our message so....
...so doing a test to see if object
is equal to null and obviously if we're testing the object that was passed to us against this
will this can't be null because this is a current object and we know it has been initialized so if the object is pass
as null we can say they aren't equal or if we saying if the class from heavenly body
or the heavenly body class is not equal to this class if they don't match basically we are going
to return false then at that point we do another test we can do...
...
...now noticed this has got an error and thereby design
so I want to point out that its a very common and easy mistake to overload the
equals method rather an overriding it so I'll say that again it is very easy to make a mistake of
overloading the equals method instead of overriding it now when typing the code it's
so easy to think that because we can be comparing heavenly body objects the
parameters to equals would be heavenly body as you can see I've put in line 37
but to guard against this always use the @ override notation when overriding
methods and you can see that's coming up with an error at the moment that and the reason
we doing that is that way if you get the method signature wrong the code is not going
to compile and you can see that we clearly got an error their
so without the ampersand override our equals method overloads the one from
the base class and ultimately it's never going to be used by the collection
class IntelliJ IDEA will automatically generated stub for you with the
annotation if you use alt insert so looking at this code we haven't actually overridden
method and again we can do an alt insert if you will if your on a PC or a Linux machine on
Mac I'm doing command n and I can go to override methods and I can come down
here to make sure I'm overriding it come down here and select equals in the
list there and notice when I do that
got a different signatures so its public boolean equals object as opposed to
heavenly body so once overloading the method this one here that we created
has actually overloaded you want to override so we want our code to be
executed equals method be executed in place of the existing equals method that
comes with an object class so what we are going to do is delete the stub I have just created
like so and come back here and going to change heavenly body to be a of type object
and if I do that notice how the override error disappeared and that's because we are
now
overriding that now of course if you didn't have override there to put that in
there you have no way of actually knowing you would assume that the code you have before was working and we
change it back to a heavenly body and it would still work but basically we wouldn't be overriding at that
point so I'm gonna undo that so we actually got our right object and this video is getting quite long
so I'm gonna stop the video here in the next video will continue on with our
discussion about equals and look at hash Code and get our sets working to remove this
duplication so I'll see you in the next video