Java Inheritance and Polymorphism

Java Inheritance and Polymorphism

This is an article about basic inheritance and polymorphism in Java Programming Language.
Let’s start by creating a class hierarchy based on animals in a zoo.
First we create the Animal base class.
The central idea is that we have a group of animals living inside a zoo.
This group of animals consists of Lions, Tigers, Cats, Hippos, Wolfs and Dogs.
They can do certain things like sleeping, roaming, making noise or eating.
Along with the things that they can do they also carry specific characteristics like the kind of food they prefer (meat or grass), how much hungry they are at a specific moment and their location in the zoo.
Their image too, is a key characteristic of every animal.

To formulate in a java class all these common characteristics we decide to create an abstract class called Animal.
The following image is a diagram of the Animal abstract class :

Animal Class

Animal Class

And here you can see the code of the Animal class:

package com.skiabox.java_apps2;
/**
* Created by administrator on 09/10/2016.
*/
public abstract class Animal {
private String picture;
private Food food;
private int hunger;
private int[][] boundaries;
private int locationX;
private int locationY;
//getters and setters
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public Food getFood() {
return food;
}
public void setFood(Food food) {
this.food = food;
}
public int getHunger() {
return hunger;
}
public void setHunger(int hunger) {
this.hunger = hunger;
}
public int[][] getBoundaries() {
return boundaries;
}
public void setBoundaries(int[][] boundaries) {
this.boundaries = boundaries;
}
public int getLocationX() {
return locationX;
}
public void setLocationX(int locationX) {
this.locationX = locationX;
}
public int getLocationY() {
return locationY;
}
public void setLocationY(int locationY) {
this.locationY = locationY;
}
//common methods
public void sleep()
{
System.out.println("The animal sleeps");
}
//methods that must be implemented below the hierarchy
public void roam()
{
System.out.println("The animal is roaming");
}
public abstract void makeNoise();
public abstract void eat();
}
view raw Animal.java hosted with ❤ by GitHub

Animal class is very general so we declare this class as abstract.
The fact that the animal class is abstract does not prevent us from writing some methods that can be used in another class or preferably to a number of classes that are positioned below the Animal class in the inheritance tree.
Notice the two highlighted lines (77 and 78).
These abstract methods must be implemented (overridden) by some class below the animal class at the hierarchy tree.

At this point we can see two more great categories of animals that introduces some more common behaviour.
For example Felines (Lions, Tigers, Cats) tend to avoid others of their own kind when they move and Canines (Wolfs, Dogs) tend to move in packs.
We can use this fact to create a couple more of abstract classes.
Let’s see the application diagram and where is the position of these two new abstract classes:

Application Diagram 1

Application Diagram 1

And here is the code of the two abstract classes :

Feline class


package com.skiabox.java_apps2;
/**
* Created by administrator on 09/10/2016.
*/
public abstract class Feline extends Animal{
//common Feline methods
public void roam() {
System.out.println("The Felines avoid each other");
}
}
view raw Feline.java hosted with ❤ by GitHub

Canine class


package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public abstract class Canine extends Animal{
public void roam()
{
System.out.println("The Canines move in packs");
}
}
view raw Canine.java hosted with ❤ by GitHub

As you can see we override here the implementation we had provided in the parent Animal class.
Let’s see how this theory behaves in action with real objects.
I have created a small application for this article and here is the code :

package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class App2 {
public static void main(String[] args) {
//Separator
System.out.println("Inheritance in action");
System.out.println("------------------------------------------------------");
Animal w = new Wolf();
w.makeNoise(); //method is called from Wolf class
w.roam(); //method is called from Canine class
w.eat(); //method is called from Wolf class
w.sleep(); //method is called from Animal class
System.out.println();
//Separator
System.out.println("Polymorphism in action");
System.out.println("------------------------------------------------------");
//Now let's create an array of animals to see polymorphism in action
Animal[] animals = new Animal[5];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Wolf(); //remember that Wolf has its own roam method
animals[3] = new Hippo();
animals[4] = new Lion();
for (int i = 0; i < animals.length; i++)
{
animals[i].eat();
animals[i].roam();
}
System.out.println();
//Separator
System.out.println("Polymorphic arguments");
System.out.println("------------------------------------------------------");
//We can have polymorphic arguments
Vet newVet = new Vet();
newVet.giveShot(w);
}
}
view raw App2.java hosted with ❤ by GitHub

If you check this code, you’ll see that at line 30 we create a new Hippo object.
You can see the Hippo class diagram and code right below :

Hippo class

Hippo class


package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class Hippo extends Animal{
@Override
public void makeNoise() {
System.out.println("The hippo snarls");
}
@Override
public void eat() {
System.out.println("The hippo is eating " + Food.GRASS);
}
}
view raw Hippo.java hosted with ❤ by GitHub

As we see here the Hippo has its own implementations of makeNoise() and eat() methods, and thus it fulfils the obligation to provide concrete implementations of abstract methods that exist above him at the class hierarchy tree.

Now we can run a small application that I have been created for this article.
Here is the application code :

package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class App2 {
public static void main(String[] args) {
//Separator
System.out.println("Inheritance in action");
System.out.println("------------------------------------------------------");
Animal w = new Wolf();
w.makeNoise(); //method is called from Wolf class
w.roam(); //method is called from Canine class
w.eat(); //method is called from Wolf class
w.sleep(); //method is called from Animal class
System.out.println();
//Separator
System.out.println("Polymorphism in action");
System.out.println("------------------------------------------------------");
//Now let's create an array of animals to see polymorphism in action
Animal[] animals = new Animal[5];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Wolf(); //remember that Wolf has its own roam method
animals[3] = new Hippo();
animals[4] = new Lion();
for (int i = 0; i < animals.length; i++)
{
animals[i].eat();
animals[i].roam();
}
System.out.println();
//Separator
System.out.println("Polymorphic arguments");
System.out.println("------------------------------------------------------");
//We can have polymorphic arguments
Vet newVet = new Vet();
newVet.giveShot(w);
}
}
view raw App2.java hosted with ❤ by GitHub

When we run this code we are getting the following result at the console window :

Inheritance in action
------------------------------------------------------
The wolf howls
The Canines move in packs
, and now that it is a wolf it is very dangerous for its prey
The wolf is eating MEAT
The animal sleeps

Polymorphism in action
------------------------------------------------------
The dog is eating GRASS
The Canines move in packs
The cat eats GRASS
The Felines avoid each other
The wolf is eating MEAT
The Canines move in packs
, and now that it is a wolf it is very dangerous for its prey
The hippo is eating GRASS
The animal is roaming
The lion is eating MEAT
The Felines avoid each other

Polymorphic arguments
------------------------------------------------------
The vet is giving a shot to Wolf
The wolf howls

Process finished with exit code 0

At line 18 the Hippo is using its own method but at the next line (19) the Hippo is using the generic roaming method from his parent Animal abstract class.

As you can see in my small program we can declare an object to be of any type above its class in the inheritance tree.
So with this array of Animal type we are getting very flexible because we can assign to the Animal variable any concrete object instance at runtime.

Now let’s turn our attention at the wolf object.
The rule here is that when you are calling an object method, the most specific version of the method is get executed.
You can see that in App2.java, lines 14-17.
Another thing to point here is that wolf’s own roam method is using its parent (Canine class) roam method by using the super keyword.
Check how this work by looking at the Wolf class diagram and code :

Wolf class

Wolf class


package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class Wolf extends Canine{
@Override
public void makeNoise() {
System.out.println("The wolf howls");
}
@Override
public void eat() {
System.out.println("The wolf is eating " + Food.MEAT);
}
//We can override a method from a superclass and at the same time call it like this
public void roam()
{
super.roam();
System.out.println(", and now that it is a wolf it is very dangerous for its prey");
}
}
view raw Wolf.java hosted with ❤ by GitHub

Let’s see now the complete inheritance tree and the rest of the various class code.

Full class tree

Full class tree


Cat class


package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class Cat extends Feline{
@Override
public void makeNoise() {
System.out.println("The cat meows");
}
@Override
public void eat() {
System.out.println("The cat eats " + Food.GRASS);
}
}
view raw Cat.java hosted with ❤ by GitHub

Dog class


package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class Dog extends Canine{
@Override
public void makeNoise() {
System.out.println("The dog barks");
}
@Override
public void eat() {
System.out.println("The dog is eating " + Food.GRASS);
}
}
view raw Dog.java hosted with ❤ by GitHub

Lion class


package com.skiabox.java_apps2;
/**
* Created by administrator on 09/10/2016.
*/
public class Lion extends Feline{
//Lion methods
@Override
public void makeNoise() {
System.out.println("The lion is growling");
}
@Override
public void eat() {
System.out.println("The lion is eating " + Food.MEAT);
}
}
view raw Lion.java hosted with ❤ by GitHub

Tiger class


package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class Tiger extends Feline{
@Override
public void makeNoise() {
System.out.println("The tiger is growling");
}
@Override
public void eat() {
System.out.println("The tiger is eating" + Food.MEAT);
}
}
view raw Tiger.java hosted with ❤ by GitHub

Finally we can use polymorphism to declare method arguments as a general type and then pass as an argument any concrete object that is of this type.
Check for example the Vet class.

package com.skiabox.java_apps2;
/**
* Created by administrator on 10/10/2016.
*/
public class Vet {
public void giveShot(Animal a)
{
System.out.println("The vet is giving a shot to " + a.getClass().getSimpleName());
//The animal reacts to the shot
a.makeNoise();
}
}
view raw Vet.java hosted with ❤ by GitHub

We can send in any animal we want and as we saw at the console window posted before every animal reacts with a different noise!
That’s all for today.
See you at my next article when we will talk about interfaces.

PS : A link with the whole project code — > Java inheritance and polymorphism Github Project

%d bloggers like this: