In Object Oriented programming (i.e. the Java programming language) Inheritance is one of the key principles that is beneficial to use in the design of any software application. Java inheritance allows for a neat way to define relationships between your Objects (and in turn re-use your code so you don't have to type the same stuff over and over again).
What is Java Inheritance
So what do I mean when I say that Inheritance allows you to define relationships between Objects? Well, let's think of some examples of Objects that DO have one or more relationships. Think the object Vehicle
, this is a fairly generic term for:
- Car
- Bus
- Motorcycle
Do you see how a Car is a Vehicle
, how a Bus is a Vehicle
, how a Motorcycle is a Vehicle
etc. This is a relationship is what Java Inheritance is all about. When you can verbally say that something
is a something else
, then you have a relationship between those two Objects, and therefore you have Inheritance.
How does Inheritance help us?
|
|
Coding Inheritance in Java
When we're coding this thing called Inheritance in Java, what does it look like? Well it can take the form of either an Interface or an Abstract Class. I'll talk more about what these are specifically in a later post, but for now all you need to know about them is this:
- Interface = An outline (or skeleton) of an Object with no implementation
- Abstract Class = An outline of an Object that can contain an implementation
Without further delay, let's look at some examples of an Interface and an abstract class.
Interface
public interface Vehicle
{
public Integer getNumberOfSeats();
public Integer getNumberOfWheels();
public String getVehicleType();
}
Here we've declared an Interface for our Vehicle
and it has three methods, getNumberOfSeats()
, getNumberOfWheels()
and getVehicleType()
. As you can see, there is no implementation of the code, we've just outlined some methods. So, now to make this interface useful, we need to implement it somewhere! So let's see what that would look like:
public class Car implements Vehicle
{
@Override
public Integer getNumberOfSeats()
{
return 5;
}
@Override
public Integer getNumberOfWheels()
{
return 4;
}
@Override
public String getVehicleType()
{
return "Car";
}
public Integer getNumberOfDoors()
{
return 2;
}
}
This is what the Car
‘s implementation of the Vehicle
interface would look like! For this example, I've stated (in code) that a Car
has 5 seats, 4 wheels and 2 doors. Let's see what a Bus
would look like:
public class Bus implements Vehicle
{
@Override
public Integer getNumberOfSeats()
{
return 35;
}
@Override
public Integer getNumberOfWheels()
{
return 6;
}
@Override
public String getVehicleType()
{
return "Bus";
}
public Integer getNumberOfDoors()
{
return 4;
}
}
Pretty self explanatory right? Well, except for those @Override
lines. What do those mean? These are called annotations and these were introduced in Java version 5 (we are currently on Java version 7). An annotation is anything that you see with an @ (at) symbol before some text above a method declaration or a class declaration. These particular @Override
annotations are just saying that the method below it are from a parent (or super) class, and we are implementing the desired behaviour in this particular class. In the case of an Interface, we have to override the methods, as it's a requirement with Interfaces.
Take special note that we don't have an @Override
annotation on our getNumberOfDoors()
method. This is because it wasn't declared in our Interface. Remember why? Because a Motorcycle
doesn't have doors, so it wouldn't make sense to put it in the Interface! Now, don't get me wrong, in the world of programming there are always several ways to solve the same problem, so you could have put something like hasDoors()
in the Vehicle
Interface and had it return a Boolean
value of true
or false
(true
in the case of Car
and Bus
, false
in the case of Motorcycle
). But, for the purpose of illustrating that you can have your own non-overridden methods in your child classes, I chose to do it the way I did it.
Abstract Class
So how about we look at abstract classes now. Remember that abstract classes don't necessarily need their methods overridden, and the methods can contain implementation if you want. If we were to create an abstract class for the Vehicle
object, it could look like this:
public abstract class Vehicle
{
public String vehicleType;
public Integer getNumberOfSeats()
{
if (this.vehicleType.equals("Car"))
{
return 5;
}
else if (this.vehicleType.equals("Bus"))
{
return 20;
}
else if (this.vehicleType.equals("Motorcycle"))
{
return 1;
}
// the vehicleType variable has not yet been set to anything,
// so we cannot say what number of seats this vehicle has, so
// we will return null.
return null;
}
public String getVehicleType()
{
return this.vehicleType;
}
public abstract Integer getNumberOfWheels();
}
So as you can see here, we have some real code implemented in our getNumberOfSeats()
method. The code relies on the vehicleType
attribute. So let's take a look at how a child class would use this Vehicle
abstract class:
public class Car extends Vehicle
{
public Car ()
{
this.vehicleType = "Car";
}
public Integer getNumberOfWheels()
{
return 4;
}
}
The first noticeable difference between an interface and an abstract class, is that you need to use the keyword implements
when you want a child class to use an Interface and you need to use the keyword extends
when you want a child class to use an abstract class. We've also done something interesting with this code:
public Car ()
{
this.vehicleType = "Car";
}
This is called a constructor. The purpose of a constructor in Java is to outline a section of code that will be executed when an Object is first instantiated. So, this just means that when someone creates an instance of our Car
Object, Java will automatically set the vehicleType
to be “Car”. I'll post a video that shows the code flow of constructors in Java, so no worries if this doesn't make sense right away.
So now, if we were to write some code get the number of seats that our Car
has, we would see that it has 5, because Java will see that the super class (Vehicle
) has a method that defines the number of seats (getNumberOfSeats()
).
Okay, so now for those who want to go the extra mile, I challenge you to put together a Java program that will allow you to use an abstract Vehicle
class and properly output the following console lines:
My Car has 2 seats.
My Car has 4 wheels.
My Bus has 20 seats.
My Bus has 6 wheels.
Using this Java main class:
public static void main(String[] args)
{
Vehicle myCar = new Car();
System.out.println("My " + myCar.getVehicleType() + " has " + myCar.getNumberOfSeats() + " seats.");
System.out.println("My " + myCar.getVehicleType() + " has " + myCar.getNumberOfWheels() + " wheels.");
Vehicle myBus = new Bus();
System.out.println("My " + myBus.getVehicleType() + " has " + myBus.getNumberOfSeats() + " seats.");
System.out.println("My " + myBus.getVehicleType() + " has " + myBus.getNumberOfWheels() + " wheels.");
}
Try your best and if you get stuck, just leave a comment on this post and I'll see what I can do to help you out! Remember, the best way to learn is to practice, practice, practice! So running into problems is a good thing, you just need to make sure you don't get frustrated an give up, so please ask me for help before you give up! Also, if you want more help with learning Java to become a full-stack developer, learn more about our Online Full Stack Developer Bootcamp here.