Inheritance
Last updated
Last updated
Essentially, it's a way of putting similar objects together to generalize behavior. Inheritance is best used with relating subtypes to larger categories. For example, an 🍊orange is a fruit (so it's a subtype of fruit).
Let's say that a supermarket named Jrader Toe's asks us to simulate fruits for them in an online system. We could do it like this:
Now, every fruit would need some of the same properties- like cost, weight, and name! So we would need to do something like:
This would be really annoying to do for every single fruit. And they're all the same properties for every fruit so it would also be incredibly inefficient code-wise. Inheritance gives a much better solution!
Let's make a Fruit class and have all of our fruits inherit from that class.
This does amazing things because we can just create one single Fruit class that has all of the properties we need, and simply make our specific fruits inherit those properties. (Side note: making multiple things inherit from one generic interface like this is called polymorphism.)
With only those 4 lines, 🍊Orange now has all of the same methods and properties that Fruit has!
You may have noticed the extends
keyword being used to specify that an object inherits from another object. This is called implementation inheritance since an object takes all of the behaviors from its parent and can use them like its own.
When extends
is used, these are the things that are inherited:
All instance and static variables that are not private (see Access Control for more information)
All non-private methods
All nested classes
These are not inherited:
Any private variables and methods
All constructors
Quick sidenote!
All objects automatically extend the Object
class whether you like it or not. See References, Objects, and Types in Java for more about this behavior.
When an object extends
another object, its constructor will automatically call the parent's constructor. However, this does have some limitations:
It will only call the default (no-argument) constructor in the parent.
Calling the constructor is the first thing that is done in the child constructor.
But what if we want to call another constructor? That's where the super
keyword comes in! When super
is called, Java will know to not call the default constructor anymore. Here's an example:
Let's say that Jrader Toe's is running a promotion for 🍐pears and wants to make them 20% off normal pears! This poses a problem because we want to inherit everything that normal pears have, but change only one behavior (getPrice). Well I've got the solution for you!!! And it's called overriding.
The @Override
tag is technically optional, but it's highly suggested because it makes sure that you are indeed overriding something and not just making a new method! (Remember, it has to have the same name and parameters as a method in one of its parents.)
Sometimes, you want to take in different parameters into the same method. For instance, what if we wanted to create a method getCount(Fruit fruit)
that counts how many fruits of that type we have? We might also want to allow users to pass in the name of the fruit to do the same thing- getCount(String fruit)
. Java will allow us to make both of these methods in the same class!
However, this has some major downsides that should be considered.
It's repetitive.
It requires maintaining more code- changing one overload won't change the others!
You can't handle any data types other than the ones you explicitly specify will work.
We'll discuss better solutions further down the page as well as in the Generic Types page!
They have very similar names but pretty different uses!
Overriding is for methods of the same name, same parameters, and different classes. If you can remember when you use the @Override
tag, you can relate it back to this concept!
Overloading is for methods of the same name, different parameters, in the same class.
Interfaces are like blueprints 📘 for objects- they tell you what an object needs, but not how to implement them.
They are very similar to normal classes except for some major differences:
All variables are constants (public static final).
Methods have no body- just a signature (like void doStuff();
)
Classes can inherit from multiple interfaces.
Typically, interfaces will not have any implemented methods whatsoever. This limitation can technically be removed using the default keyword, but this is not recommended because abstract classes handle this much better.
Here's an example of interfaces in the wild:
Abstract classes live in the place in between interfaces and concrete classes. In a way, they get the best of both worlds- you can implement whichever methods you want, and leave the rest as abstract methods (same behavior as interface methods)!
Here are some properties:
Variables behave just like a concrete class.
Normal methods can be created like any other concrete class.
Abstract methods (abstract void doSomething()
) behave just like methods in interfaces.
Classes can only inherit from one abstract class.
Here's the same example from the interfaces section, but implemented using an abstract class.
Watch Josh Hug's video lecture about inheritance.
Or, move onto an advanced application of inheritance concepts, Dynamic Method Selection.