ok so it is time for a challenge now this is only going to be a real small
challenge there's no coding necessary but I'm gonna type the challenge so you have
it on the screen and then going to talk through it because it's important
and after this after we have gone through the answer I'm just gonna demonstrate the concepts so
what I'm going to do is create a new class now I'm gonna call it challenge because that's
what we're going to be typing some of the code or this code anyway so we are gonna call it challenge, oops I called it the wrong this so will just refactor and rename and get rid of one of the ls
so paste that in ok so here is the challenge
so when overriding the equals method in the heavenly body class we were careful
to make sure that it would not return true if a heavenly body was compared to a
subclass of itself now I did that we did that to demonstrate that method but it was
actually unnecessary in the heavenly body class it self so your challenged
is just a question and that question is why was it unnecessary to do that for the
heavenly body class and just a hint there if you stuck check out lecture
97 because that goes through what the issue is and why in this case it's not
necessary so pause the video and see if you can have a bit of a think and figure
out why its not needed and if necessary go back and
review heavenly body the code and when you ready start the video
pause the video now ok so how did you get on hopefully you figure out the
answer to the question which was why is it unnecessary to do that check in the
heavenly body class to make sure that it wouldn't return true if a heavenly body was
compared to a sub class of itself so I'm going to paste the answer here and then we'll talk
about it and we're gonna go through some code ok so there is
the answer the heavenly body classes declared final so it can't
be sub class so of course we didn't need to do any tests to check the sub class
because we already know that is mark final and in addition the Java String class is also
final and that's why it's which is why it can safely use the instance of method
without having to worry about comparisons with a subclass that's the
answer to that hopefully you figured that out and again if unsure check out lecture
97 but you might be looking at and thinking why is it an issue with using
instance of it in sub classes so what I'm going to do is create some additional
code now to show you an outline what the problem is so we can actually do this in
this code in this class you can create a new project if you want but I'm just gonna put it in this
project so I'm going to create a class start off and call it dog dogs is gonna be a base class
and we are gonna have a final field...add our constructor which accepts as a parameter
and we just have a getter for name so the actual equals method that we are going to write we are going
to override it so I'm going to do a ctrl O and override equals and instead of that
return and firstly if this is equal to object
return true remember when we do that to test whether this object is being compared
against itself and if that's the case and it's the same object in memory we
know there's always going return true using a equals equals so if that's the case we will
return as you can see in line 20 but next we want to do if...
..which is the object that we are comparing...
...
...ok so that's the
case and we determined that if the strings in the classes are the same and is the dog class
that were actually comparing that's the case we get the strings or we use the string equals
to actually check test whether the strings is the same if you get this far down and we know
that they weren't the same so we are going to return false so next we are going to create another class now and call this
one labrador and going to extend or subclass dog
..and create a constructor first it is going to correctly call the super to set the dog
name and we don't need to do anything else other than the equals so what I'm going to do with the equals is I'm
copy the equals method from dog and we just going to make a change a couple of changes so we are just going to
paste that in so there's our overridden method for equals and the only change to make
is the references to dog we are gonna change to labrador so take a copy of
the class and change that to Labrador and ObjectName to labrador as well so it
is now testing correctly for this class instead of its super class which
was dog name is not going to work anymore that's because we haven't got a field
in this class and we set it to private access so we are going to change that and use
.getName so that we can actually get access to the name that was saved on
line 9 when the constructors was actually called you can see now its correctly
comparing Labrador and create another class and we will call it DogMain so as not to confuse ourselves with the
original main class that we use earlier in this set of videos and we are going to create ourselves
a main method so we can run it so type...there is our main method so we can
actually call so gonna create a pet Labrador called rover so rover is found
wondering by the dog warden who reads her collar and decides she's a dog called
Rover so lets do that so...so we are very
distraught at this point at the loss of our pet so we're going to call the dog pound to see
if she's been found now they have a dog and dog is called rover but is she
our pet well that depends on how you ask the questions so what we can do in
programming terms to answer that question
we can put firstly does..
...and the second
test will be....
so we've done the first one the testing rover against rover 2 and the second one we're testing rover 2
against rover firstly run that and it doesn't work because it is executing the other
class so right click again run so I'm gonna click on run dog main so you might be interested
to see that in the first case rover two equals rover rather but in the 2nd case it
returned true for that first but on the 2nd one line 12 rover equals
rover 2 return false so what is happening here is a Labrador is an
instance of dog but dog though is not an instance of Labrador so the second test
returns false so this violates that symmetric rule that we talked about that
and equals method must obey so basically has to be equal on both sides of the
coin in this case rover 2 has to equals rover if we are testing in that way but the
other way around as well rover has to equal rover 2 for that to be true so we
can fix this because it's obviously a problem at the moment so we can
best way to fix is to not override the equals method in Labrador so we can
remove that code so we're going to remove the lines from Labrador
so go back in there and do that so I'm going to basically comment out this code
in the Labrador class we're not going to override equals at all I'm just going to commenting that out completely so
that should now now that we've done that if we go back to dog main we should allow us to find a pet regardless
of how the questions is phrase so we will just run first to confirm notice it's now true in both
scenarios because we are not overriding that equals it's now set to true in both cases whichever the way
the questions phrase in other words now to ensure that equals can't be overridden
in sub classes of dog what we want to do to confirm that we would is to actually go
back to the dog class and marked that as final...so we are marking that as final and we are saying that this
method cannot be overridden at that point so
that's one way to really make sure that the equals can't be overridden and
we can't get into the problems that we just had so what we could do is go back to
Labrador and if we try to uncomment this code we're now gonna get an error and
basically its saying the overridden method is final so we can't do what we're trying to do so
that's the message we want in this case so I'm going to comment that again and will do another test to make
sure that its still running and we are getting true for both so what this should highlight is
that it really does show that a great deal of thought is needed when you're
overriding equals and of course therefore hash code so should you allow your
classes to be sub classed if so how do you treat comparisons between the subclass
and its base class so if the subclass would reasonably only add methods that do not alter
the way that equal should work then allow sub classing but Mark you equals
and hashCode method as final now if a sub classes is likely to be different object
then used the method we use in heavenly body to make comparisons between the
subclass and its base class return false if needed these would really fit then
prevent sub classing and force clients to use composition instead so we now seen how to
implement a immutable class that can be safely used as either a key in a map or as
an element in the set the heavenly body class isn't immutable because we can add
moons to it but any change would make too it won't affect either behavior of
equals or the hash code that it generated by its hash code method and it's worth
pointing out that these videos have been about sets and overriding equals and
hashCode and not about how best to model the universe so keep that in mind that
its important distinction there and the example using planets was chosen really because
it involved objects naturally form sets and it was quite good for
demonstrating sets and also because I wanted to have sets of objects rather
a primitive type so that we could look at equals and hashCode now there's a definite is a
relationship between a heavenly body and both a moon and a planet though so if
you were really modeling the universe it would probably be better to extend a
base class to create the different types of objects found in space
sets could still be useful though so if you program was used by someone
investigating ice giants for example that it could be useful to group
that kind of planet into its own set and a planet object could maintain its set of moons and could then be used in
a union to allow all the moons in the solar system to group together as we did
course in the examples so that's it i hope you've got a lot out of these few
videos in the next video we are going to look at set intersection and difference and we are going to
finish with a meaty challenge so I'll see you in the next video