TIL: Inheritance pt2
We’re going to continue where we left off yesterday and discuss a few more things related to inheritance.
Now that we have a good understanding of how inheritance works there’s a few more things to cover to round out our understanding.
Final
When defining your class and methods, you have a variety of keywords available to tag onto definition. This typically would go in front of the type declaration. One of these keywords is final
.
What does final
do? It tells the compiler that either the class or the method cannot be extended or overwritten, respectively. This can be handy if you’re trying to lock down the class and prevent someone from using it outside of your defined purpose.
Let’s take the examples from the lessons yesterday. Let’s suppose I decide that I don’t want someone to be able to extend the Dog
class. I can lock this down by adding a final
to the class definition:
|
|
By adding the final to the entire class, our Shiba
class will no longer be able to extend Dog
and now starts to throw errors.
We can do the same thing with individual methods as well. Recall from before that we had defined our Shiba
class to @Override
the makeSound()
method from the base Animal
class:
|
|
If I were to go into the base Animal
class and mark the makeSound()
method as final
, we’ll see that we get an error present in the Shiba
class for the @Override:
|
|
Abstract
So just like you can prevent a class from being extended or class being overridden, you can also require that a class be extended or that a method be overridden. That’s where the abstract
keyword comes in.
When using abstract
, there’s two rules to follow:
- If marking a method as
abstract
you must mark the class asabstract
- If marking a class as
abstract
you DO NOT need to mark any methods asabstract
Number two above is not very common, but it is possible to do.
Using our examples from before, we could change both our Animal
and Dog
classes to be abstract
and our tests would still continue to pass. But what about methods?
When defining an abstract
method, you will need to define it without any body. You can define the name, the return types and the accepted parameters, but you cannot define any logic to it. This means that every class that inherits this method will need to define their own logic.
Let’s add in a new abstract
method into our base Animal
class:
|
|
Notice how there is no body (curly braces) in the definition. If you try to even put them in, even if they’re empty, you will get errors.
Now let’s write our method inside of the Dog class:
|
|
That will clean up all of errors and allows the method to be specific to the inherited class.
Object Comparisons
This is more of a “good to know” rather than directly related to the inheritance that we’ve been talking about.
As mentioned in yesterday’s post, everything inherits from the Object
class. Along with Object
comes the equals()
method. By default, this equals method will only validate whether two references point to the same object in memory.
That’s to say, if I were to create two different instances to two different Dog
objects and then see if they are equal, it would return false:
|
|
However, if we tweaked this a little bit and had b pointing to a, then this would be true:
|
|
Using @Override
like we learned yesterday, we can actually change the equals()
method on a per class basis so that it does exactly what we want it to do. So instead of comparing whether or not it’s the exact same object, we could check to see if it’s two Dog
classes with the same breed or name or something like that.
Conclusion
That wraps up everything I wanted to talk about regarding inheritance. That should be a pretty good start to get you going. As always, the code from this lesson is available on my github page.
💚 A.B.L.