Inheritance In Java

The concept of inheritance is straightforward but powerful.

When you want to create a new class and there is an existing class that contains some of the code you want, you can create your new class from the existing class. This allows you to reuse the existing class's fields and methods without having to write (and debug!) them yourself.

We group the “inheritance concept” into two categories:

image 32 - Inheritance In Java

Use the extends keyword to inherit from a class.

A subclass inherits all of its superclass’s members (fields, methods, and nested classes). Constructors are not members, so they are not inherited by subclasses; however, the superclass’s constructor can be invoked from the subclass.

A subclass is a class that is derived from another class (also called a derived class, extended class, or child class). A superclass is the class from which the subclass is derived (also called a base class or a parent class).

Except for Object, which has no superclass, each class has a single and unique direct superclass (single inheritance). Every class is implicitly a subclass of Object in the absence of any other explicit superclass.

Classes can be derived from classes that are derived from classes that are derived from classes, and so on, and ultimately derived from the topmost class, Object. Such a class is said to be descended from all the classes in the inheritance chain stretching back to Object.

Inheritance Syntax in Java

image 33 - Inheritance In Java

General format for Inheritance

image 34 - Inheritance In Java

The extended keyword extends a class and indicates that another class has inherited it. When you say that class B extends class A, you mean that class B inherits the properties (methods, attributes) of class A. Class A is the superclass or parent class in this case, and class B is the subclass or child class.

Inheritance Program Example

class Base {
    public void method1() {
        System.out.println(" Base Class Method ");
    }
}

class Derived extends Base{
    public void method2() {
        System.out.printIn(" Derived Class Methods ");
    }
}

public class InheritanceTest
    {
        public static void main(String[] args) {
            Derived d = new Derived(); // creating object
            d.method1(); // print Base Class Method
            d.method2(); // print Derived Class Method
    }
}

The Java Platform Class Hierarchy

The Object class is defined in java.lang package defines and implements behavior that is common to all classes, including your own. Many classes in the Java platform derive directly from Object, while others derive from some of those classes, and so on, forming a class hierarchy. All Classes in the Java Platform are “Descendants” of Objects.

image 35 - Inheritance In Java

The object is the most general of all classes at the top of the hierarchy. More specialized behavior is provided by classes near the bottom of the hierarchy.

What You Can Do In A Subclass?

No matter what package a subclass is in, it inherits all of its parent’s public and protected members. If the subclass is in the same package as its parent, it inherits the parent’s package-private members as well. We will discuss this in great detail when we discuss the package.

  • The inherited members can be used as is, replaced, hidden, or supplemented with new members.
  • The inherited fields, like any other fields, can be used directly.
  • You can hide a field in the subclass by declaring it with the same name as the one in the superclass (not recommended).
  • You can add new fields to the subclass that are not present in the superclass.
  • The inherited methods can be used directly as they are.

You can write a new instance method in the subclass that has the same signature as the one in the superclass, thus overriding it. We will discuss overriding later in this tutorial.

You can hide a method in the subclass by creating a new static method in the subclass with the same signature as the one in the superclass.

In the subclass, you can declare new methods that are not in the superclass.

You can write a subclass constructor that, either implicitly or explicitly, calls the superclass constructor.

Understanding Inheritance

When you use inheritance in your design, you put common code in a class and then tell other more specific classes that the common (more abstract) class is their superclass. The subclass inherits from the superclass when one class inherits from another.

In Java, this is referred to as the subclass extends the superclass.

An inheritance relationship implies that the members of the superclass are passed down to the subclass. When we say “class members,” we mean instance variables and methods.

The Car class (subclass) in the following example inherits the attributes and methods from the Vehicle class (superclass):

public class Vehicle {
    public String brand;        // Vehicle attribute
    public String model;
   
    public void setBrand(String b){
        brand = b;
    }
    public String getBrand(){
        return brand;
    }

    public void setModel(String m){
        model = m;
    }
    public String getModel(){
        return model;
    }

    public void honk() {                    // Vehicle method
        System.out.println("Tuut, tuut!");
  }
}

class Car extends Vehicle {

    boolean autoTransmission;
    int noOfSeats;

    public void setAutoTransmission(boolean b){
        autoTransmission = b;
    }
    public boolean getAutoTransmission(){
        return autoTransmission;
    }

    public void setNoOfSeats(int seats){
        noOfSeats = seats;
    }
    public int getNoOfSeats(){
        return noOfSeats;
    }

}

class InheritanceTest{
    public static void main(String[] args) {
        Car car = new Car();
        car.setBrand("Ford");
        car.setModel("Mustang");
        car.setAutoTransmission(true);
        car.setNoOfSeats(4);
        car.honk();
    }
}

To further understand the inheritance let us design the inheritance tree for a Simulation program.

Assume you've been tasked with creating a simulation program that allows the user to toss a variety of animals into an environment to see what happens. We don't need to code the thing right now because we're more interested in the design.

Some of the animals in the program have been given to us, in a list, but not all. We know that each animal will be represented by an object, and that the objects will move around the environment doing whatever each type is programmed to do.

We also want other programmers to be able to add new animal types to the program at any time.

First, we must identify the common, abstract characteristics shared by all animals and organize those characteristics into a class that all animal classes can extend.

image 36 - Inheritance In Java

Using Inheritance To Avoid Duplicating Code In Subclass

We have five instance variables:

image 37 - Inheritance In Java

We have the following four methods:

image 38 - Inheritance In Java
Create a class to represent the common state and behavior.

Because these objects are all animals, we’ll create a superclass called Animal. We’ll include methods and instance variables that all animals may require.

Determine whether a subclass requires subclass-specific behaviors (method implementations).

We decide, by looking at the class, the Animal class’s eat() and makeNoise() methods should be overridden by the individual subclasses.

Do all the animals eat the same way?

Assume we are all in agreement on one point: the instance variables will work for all Animal types. A lion will have his own image, food (we’re thinking meat), hunger, boundaries, and location values. A hippo’s instance variables will be different, but he will still have the same variables as the other Animal types. The same goes for a dog, a tiger, and so on.

What about behavior, though?

Which methods should we override?

Does a lion make the same noise as a dog? Does a cat eat like a hippo? Perhaps in your version, but in ours, eating and making noise are Animal-type specific.

We can’t figure out how to code those methods so that they work for any animal. That’s not correct. We could write the makeNoise() method so that it only plays a sound file defined in an instance variable for that type, but that’s not very specialized. Some animals may make different noises in different situations (for example, one when eating and another when running into an enemy).

We’ll need to do the “method overriding” for our Animal subclasses to get more animal-specific (in other words, unique) behavior.

We will explain method overriding in the next section of this tutorial.

Look for more inheritance opportunities

Look for additional opportunities to use abstraction by identifying two or more subclasses that may require common behavior.

The class hierarchy is taking shape. We have each subclass override the makeNoise() and eat() methods so that there is no confusion between a Dog bark and a Cat meow (which is quite insulting to both parties). And a Hippo will not eat like a Lion.

But maybe there’s more we can do. We must examine the Animal subclasses to see if two or more can be grouped together in some way and given code that is unique to that new group. Wolf and Dog share characteristics. Lion, Tiger, and Cat also do. We look at our classes and notice that Wolf and Dog have some behavior in common, as do Lion, Tiger, and Cat.

Finish the class hierarchy

We can use the level that makes the most sense for class design because animals already have an organizational hierarchy (the whole kingdom, genus, phylum thing). We’ll organize the animals into Feline and Canine classes using biological “families.”

Because Canines tend to move in packs, we decide that they could benefit from a common roam() method. We can also see that Felines could use a common roam() method because they avoid other felines. We’ll let Hippo keep using its inherited roam() method, which it gets from Animal. This is it now for designing, we’ll come back to it later in the tutorial.

Method Overriding

In Java, method overriding occurs when a subclass (child class) has the same method as the parent class.

In other words, Method overriding is the act of declaring a method in a subclass that is already present in the parent class. Overriding is done so that a child class can provide its own implementation to a method that the parent class already provides. In this case, the method in the parent class is referred to as an overridden method, and the method in the child class is referred to as an overriding method.

Method overriding is used to provide a specific implementation of a method that its superclass already provides.

For runtime polymorphism, method overriding is used. Do not worry about the polymorphism right now. It will come in due time.

Java Method Overriding Guidelines

image 39 - Inheritance In Java

public class Animal {
    //overridden method
    public void eat() {
        System.out.println("This is Animal Class");
    }
}
 
class Cat extends Animal {
    //overriding method
    public void eat() {
        System.out.println("This is Cat class");
    }
}
class TestMainEat {
 
    public static void main(String args[]) {
        Animal a = new Animal(); // Animal reference and object
        Animal c = new Cat(); // Animal reference but Cat object
 
        a.eat();// runs the method in Animal class
        c.eat();// Runs the method in Cat class
    }
}

Which Method Is Called?

Even though c is a type of Animal, the move method in the Cat class is called in the preceding example.

The reason for this is that the reference type is checked during compilation. However, during runtime, the JVM determines the object type and executes the method associated with that object. When you call a method on an object reference, you are calling the method’s most specific version for that object type.

In other words, the lowest one wins!

“Lowest” refers to the position at the bottom of the inheritance tree.

Now let us look at our simulation program.

There are four methods in the Wolf class. One is inherited from Animal, one from Canine (which is actually an overridden version of a method in the Animal class), and two are overridden in the Wolf class. When you create a Wolf object and assign it to a variable, you can invoke all four methods by using the dot operator on that reference variable. But which of those methods is invoked?

Wolf w = new Wolf();//make a new Wolf object
w.makeNoise();//calls the version in Wolf
w.roam();//calls the version in Canine
w.eat();//calls the version in Wolf
w.sleep();//calls the version in Animal

Because Canine is lower than Animal and Wolf is lower than Canine, invoking a method on a Wolf object causes the JVM to look first in the Wolf class. If the JVM does not find a version of the method in the Wolf class, it proceeds to walk up the inheritance hierarchy until it finds a match.

Q: You stated that the JVM begins walking up the inheritance tree, beginning with the class type on which you invoked the method (similar to the Wolf example on the previous example). But what if the JVM is unable to find a match?

That’s an excellent question! But you don’t have to be concerned about that. At runtime, the compiler guarantees that a specific method is callable for a specific reference type, but it doesn’t say (or care) which class that method actually comes from. In the Wolf example, the compiler looks for a sleep() method but is unconcerned that sleep() is defined in (and inherited from) class Animal. Remember that if a class inherits a method, the method is available to it.

The compiler is unconcerned about where the inherited method is defined (that is, in which superclass it is defined). However, the JVM will always select the correct one at runtime. And the best one is the most specific.

What is the meaning of the “IS-A” and “HAS-A” relationship?

In object-oriented programming, this is a common way to depict inheritance versus composition.

Remember that when one class inherits from another, the subclass is said to extend the superclass. Use the IS-A test to determine whether one thing should extend another.

image 41 - Inheritance In Java

To determine whether you’ve designed your types correctly, ask yourself, “Does it make sense to say type X IS-A type Y?” If it doesn’t, you know something is wrong with the design. So if we apply the IS-A test, Ball IS-A a Tennis is definitely wrong.

If we reverse the relationship and ask ourselves if Tennis is a Ball that still does not work.

Though Tennis and ball are related, it is not through inheritance. They are joined by a HAS-A relationship. Does it make sense to say, “Tennis has a Ball”? If the answer is yes, then it means that Tennis has a ball instance variable. To put it simply, Tennis has a reference to a Ball, but Ball does not extend Tennis, and vice versa.

The IS-A test is applicable anywhere in the inheritance tree. When you ask any subclass if it IS-A any of its supertypes, the IS-A test should make sense if your inheritance tree is well-designed.

image 43 - Inheritance In Java

With an inheritance tree like this one, you can always say “Wolf extends Animal” or “Wolf IS-A Animal.”

It makes no difference whether Animal is the superclass of Wolf’s superclass. In fact, Wolf IS-A Animal will always be true as long as Animal is somewhere in the inheritance hierarchy above Wolf.The structure of the Animal

inheritance tree says to the world:

“Wolf IS-A Canine, so Wolf can do anything a Canine can do. And Wolf IS-A Animal, so Wolf can do anything an Animal can do.”

It makes no difference if Wolf overrides some of the Animal or Canine methods. A Wolf is capable of those four methods in the world (of other code). It makes no difference how he does them or in which class they are overridden. Because a Wolf extends from the class Animal, it can makeNoise(), eat(), sleep(), and roam().

How Do You Know If You’ve Got Your Inheritance Right?

There’s obviously more to it than what we’ve covered so far, but we’ll look at a lot more OO issues in the next chapter (where we eventually refine and improve on some of the design work we did in this chapter).

For the time being, however, the IS-A test is a good starting point. If “X IS-A Y” makes sense, both classes (X and Y) should probably be in the same inheritance hierarchy. They almost certainly exhibit similar or overlapping behaviors.

Keep in mind that the inheritance IS-A relationship works in only one direction!

Triangle IS-A Shape makes sense, so Triangle extend Shape is possible.

However, the converse—Shape IS-A Triangle—doesn’t make sense, so Shape should not extend Triangle. Keep in mind that the IS-A relationship implies that if X IS-A Y, then X can do anything that a Y can do (and possibly more).

Q: So we see how a subclass gets to inherit a superclass method, but what if the superclass wants to use the subclass version of the method?

A superclass is unlikely to be aware of any of its subclasses.

You might create a class, and then someone else comes along and expands on it. Even if the superclass creator is aware of (and wishes to use) a subclass version of a method, there is no reverse or backwards inheritance. Consider this: children inherit from their parents, not the other way around.

Q: What if I want to use BOTH the superclass version and my overriding subclass version of a method in a subclass? In other words, I don’t intend to completely replace the superclass version; rather, I intend to augment it.

You can do it! It’s also an important design feature. Consider the word “extends” to mean “I want to extend the functionality of the superclass.”

You can design your superclass methods so that they contain method implementations that will work for any subclass, even if the subclasses will still need to ‘append’ more code. The keyword super can be used in your subclass overriding method to call the superclass version. It’s equivalent to saying, “First, run the superclass version, then come back and finish my own code…”.

public void roam() {
super.roam();
// my own roam stuff
}

Members of the superclass are inherited by a subclass. Members include instance variables and methods, but we’ll look at other inherited members later in this course. A superclass can choose whether or not to allow a subclass to inherit a specific member based on the level of access that member is granted.

This course will go over four different levels of access.

The four access levels are, in order of most restrictive to least restrictive:

image 44 - Inheritance In Java

Access levels control who sees what and are essential for well-designed, robust Java code. For the time being, we’ll stick to public and private. For those two, the rules are straightforward:

public members are inherited
private members are not inherited

When a subclass inherits a member, it is the same as if the subclass created the member. Square inherited the rotate() and playSound() methods from Shape, and to the outside world (other code), the Square class simply has a rotate() and playSound() method.

A class’s members are the variables and methods defined in the class, as well as anything inherited from a superclass.

So what does all this inheritance really buy you?

Designing with inheritance gives you a lot of OO mileage. Duplicate code can be avoided by abstracting out the behavior shared by a group of classes and placing it in a superclass. When you need to change it, you only have to update one place, and the change is magically reflected in all the classes that inherit that behavior. Well, There is no magic involved, but it is quite simple: make the change and recompile the class. That’s all.

You don’t have to touch the subclasses! Just deliver the newly-changed superclass, and all classes that extend it will automatically use the new version.

Because a Java program is nothing more than a collection of classes, the subclasses do not need to be recompiled in order to use the new version of the superclass. Everything is fine as long as the superclass does not break anything for the subclass. (We’ll talk about what the term “break” means in this context later in the course.) For the time being, think of it as changing something in the superclass on which the subclass relies, such as a specific method’s arguments, return type, or method name, etc.).

1 You avoid duplicate code.

Put all common code in one place and let subclasses inherit it from a superclass. When you want to change that behavior, you only need to change it once, and everyone else (i.e. all the subclasses) will notice.

2 You define a common protocol for a group of classes.
Share The Tutorial With Your Friends
Twiter
Facebook
LinkedIn
Email
WhatsApp
Skype
Reddit

Check Our Ebook for This Online Course

Advanced topics are covered in this ebook with many practical examples.