Inheritance BasicsS2C Home « Inheritance Basics

Inheritance is a language mechanism, that allows us to group common characteristics together into a set of related items, which we can then redefine into more specific subsets. In Java terminology, the general class that holds the group of common characteristics is known as the superclass and the specialised subset of this is known as the subclass. We achieve this hierarchial connection in Java using the extends keyword, wherein the subclass extends the superclass. By extending like this we have created an inheritance hierarchy where the subclass inherits the traits of the superclass, in other words the members of the superclass, assuming the access modifiers permit inheritance. Because the subclass is more specialised it can override the instance methods members of the superclass and also add new members of its own.

We used some new terminology there for members, did you notice? Yes we said override as opposed to overload, which we have already come across in the Objects & Classes section, in the Methods lesson. When we override the instance method members of the superclass in a subclass, we are writing a more specific method for use by the subclass that overrides the inherited method. We will go into overriding in much more detail in the Overriding Methods section, later in the lesson.

We do not override instance variables in a subclass with the same identifier in the superclass. This is known as hiding and will be discussed in the next lesson in Superclass Members.

We do not override static methods in a subclass with the same identifier in the superclass as these are class methods and not related to any instance. This is also known as hiding and will be discussed, paradoxically in the lesson on Polymorphism. Following is a slideshow to digest the information we have written so far about inheritance:

inheritance 1 inheritance 2 inheritance 3 inheritance 4

All is good in Vehicle Town, we have our vehicle class and everyone is happy. But wait, people without cars want to get on a bus and people want trucks to transport goods. Let's use inheritance, rather than write new classes and replicate a lot of things that all vehicles can do

The first thing we do is make a Car class, which is all our original Vehicle class held; so we don't need to change anything here.

Our new Bus class comes next and we need a new instance variable conductor.

Last is our Truck class, in which we are going to override the carry() method from the Vehicle class.

Press the button below to cycle through our Inheritance explanation.


Our Vehicle superclassgo to top of page Top

Here we code and test the Vehicle class which is just a normal class like any other we have seen so far. This class holds all the generic stuff our subclasses will need in one place, thus avoiding code duplication.


/*
  A Vehicle Class
*/ 
public class Vehicle {
    private String chassis;
    private String motor;
    private int wheels;
    /*
      Public getters and Setters
    */ 
    public String getChassis() {
        return chassis;
    }
    public void setChassis(String chassis) {
        this.chassis = chassis;
    }
    public String getMotor() {
        return motor;
    }
    public void setMotor(String motor) {
        this.motor = motor;
    }
    public int getWheels() {
        return wheels;
    }
    public void setWheels(int wheels) {
        this.wheels = wheels;
    }
    /*
      Instance Methods
    */ 
    public void service(int month) {
        System.out.println("Our vehicle needs servicing every " + month + " months."); 
    }
    public void carry(int carry) {
        System.out.println("Our vehicle carries " + carry + " passengers."); 
    }
    public void load(String load) {
        System.out.println("Our vehicle is loaded with " + load); 
    }
}

Save and compile our Vehicle class in directory   c:\_OOConcepts in the usual way.

Ok our instance variables have the private access modifier so these members are only accessible within the Vehicle class or through their getters and setters. Now lets test our new Vehicle class:


/*
  Test Class for Vehicle
*/ 
public class TestVehicle {

    public static void main (String[] args) {
        Vehicle saloon = new Vehicle();
        saloon.setChassis("2-axle chassis");
        saloon.setMotor("4 stroke");
        saloon.setWheels(4);
        System.out.println("Our vehicle has a " + saloon.getChassis() + ", " + saloon.getMotor() 
                                                + " motor and has " + saloon.getWheels() + " wheels.");
        saloon.service(12); 
        saloon.carry(4); 
        saloon.load("shopping."); 
    }
}

Save, compile and run the file in directory   c:\_OOConcepts in the usual way.

run vehicle class

The above screenshot shows the output of testing our Vehicle class.

Using the extends keywordgo to top of page Top

As metioned earlier in the lesson we create an inheritance tree in Java using the extends keyword, wherein the subclass extends the superclass. By extending like this we create an inheritance hierarchy where we can use the more abstract superclass members, as well as more specific subclass member overrides where required.

Ok, time to code up the first three classes of the hierarchy shown in the slide show above, starting with the Car class.

Our Car subclassgo to top of page Top

Here we code and test the Car subclass where we use the extends keyword for the first time to subclass the Vehicle class. The Car class is very simple as it just uses all the same members as its superclass, the Vehicle class.


/*
  A Car Class
*/ 
public class Car extends Vehicle {

}

Save and compile our Car subclass in directory   c:\_OOConcepts in the usual way.

When using the extends keyword to extend a class an important point to remember is you can only extend one class in Java. You can't say for instance:


public class Car extends Vehicle, Motorized {

}

As you will get a compiler error. We will go into more detail of this later in the section, for now lets test the new Car subclass to make sure it works:


/*
  Test Class for Car
*/ 
public class TestCar {

    public static void main (String[] args) {
        Car estate = new Car();
        estate.setChassis("2-axle chassis");
        estate.setMotor("6 valve");
        estate.setWheels(4);
        System.out.println("Our car has a " + estate.getChassis() + ", " + estate.getMotor() 
                                            + " motor and has " + estate.getWheels() + " wheels.");
        estate.service(12); 
        estate.carry(6); 
        estate.load("shopping."); 
    }
}

Save, compile and run the file in directory   c:\_OOConcepts in the usual way.

run car class

The above screenshot shows the output of testing our Car subclass. The class works as intended and uses all its inherited members of the Vehicle superclass to output some messages. Time to code up our second subclass, the Bus class:

Our Bus subclassgo to top of page Top

Here we code and test the Bus subclass where we use the extends keyword again to subclass the Vehicle class. With the Bus class we need to add a new instance variable conductor to the class. The superclass Vehicle has the rest of the stuff we need.


/*
  A Bus Class
*/ 
public class Bus extends Vehicle {
    private boolean conductor;
    /*
      Public getters and Setters
    */ 
    public boolean getConductor() {
        return conductor;
    }
    public void setConductor(boolean  conductor) {
        this.conductor = conductor;
    }

}

Save and compile our Bus subclass in directory   c:\_OOConcepts in the usual way.

Lets test the new Bus subclass to make sure it works:


/*
  Test Class for Bus
*/ 
public class TestBus {

    public static void main (String[] args) {
        Bus a1 = new Bus();
        a1.setChassis("4-axle chassis");
        a1.setMotor("12 stroke");
        a1.setWheels(8);
        a1.setConductor(false);
        System.out.println("Our bus has a " + a1.getChassis() + ", " + a1.getMotor() 
                                            + " motor and has " + a1.getWheels() + " wheels.");
        if (a1.getConductor()) {
            System.out.println("This bus has a driver and a conductor."); 
        } else {
            System.out.println("This bus has a driver only."); 
        }                                    
        a1.service(3); 
        a1.carry(60); 
        a1.load("people."); 
    }
}

Save, compile and run the file in directory   c:\_OOConcepts in the usual way.

run bus class

The above screenshot shows the output of testing our Bus subclass. The class works as intended and uses all its inherited members of the Vehicle superclass as well as the new instance varible conductor to output some messages.

Overriding Methodsgo to top of page Top

We just have one more subclass to code in our simple inheritance tree, the Truck subclass. This class overrides the carry() method from the Vehicle superclass. This is our first look at coding a method override and so we will just cover the basics and rules in this lesson. A method override must adhere to the contract it has with the superclass method. This contract being, a method override must have exacly the same arguments and return type (or co-variant thereof) as the superclass method with the same method name. This is different to our examples of overloaded methods in the Objects & Classes section, in the Methods lesson, in which the argument lists had to be different. In fact if you change the argument lists, that's what you end up with an overloaded method. So to make sure we are doing a method override we need to keep the contract. Time to code up our Truck subclass.

Our Truck subclassgo to top of page Top

Here we code and test the Truck subclass where we use the extends keyword again to subclass the Vehicle class. With the Truck class we need to override the carry() method from the Vehicle superclass. The superclass Vehicle has the rest of the stuff we need.


/*
  A Truck Class
*/ 
public class Truck extends Vehicle {

    /*
      Our carry() override method
    */ 
    void carry(int tonnage) {
        System.out.println("Our truck can carry up to " + tonnage + " tons of cargo."); 
    }
}

Save and compile our Truck subclass in directory   c:\_OOConcepts in the usual way.

run truck class

The above screenshot shows the output of compiling our Truck subclass. We got a compiler error and the error message is quite informative for this one. So lets take a look at what happened:


/*
  The carry() method in the Vehicle superclass
*/
 public void carry(int carry) { ... }  // We used the public access modifier

/* The override carry() method in the Truck subclass */ void carry(int tonnage) { ... } // We didn't put an access modifier on so its package-default

When we override a method, the overriding method can't be less accessible.

In our example it is so lets correct the override method and put the public access modifier at the start of the carry() method:


/*
  A Truck Class
*/ 
public class Truck extends Vehicle {

    /*
      Our carry() override method
    */ 
    public void carry(int tonnage) {
        System.out.println("Our truck can carry up to " + tonnage + " tons of cargo."); 
    }
}

With the changes to the Truck subclass save and recompile it, it should compile fine now.

Lets test the new Truck subclass to make sure it works:


/*
  Test Class for Truck
*/ 
public class TestTruck {

    public static void main (String[] args) {
        Truck arctic = new Truck();
        arctic.setChassis("3-axle chassis");
        arctic.setMotor("12 stroke");
        arctic.setWheels(12);
        System.out.println("Our truck has a " + arctic.getChassis() + ", " + arctic.getMotor() 
                                            + " motor and has " + arctic.getWheels() + " wheels.");
        arctic.service(3); 
        arctic.carry(10); 
        arctic.load("trade goods."); 
    }
}

Save, compile and run the file in directory   c:\_OOConcepts in the usual way.

run truck test

The above screenshot shows the output of testing our Truck subclass. The class works as intended and uses the inherited members of the Vehicle superclass, our carry() method override to output some messages.

Overriding Method Rulesgo to top of page Top

So when we override a superclass method there are some rules to adhere to:

  • A method override must have exacly the same arguments as the superclass method with the same method name or you end up with an overloaded method.
  • A method override must have the same return type (or co-variant thereof) as the superclass method with the same method name.
  • When we override a method, the overriding method can't be less accessible, but can be more accessible.
  • You cannot override a method marked with the final modifier.
  • You cannot override a method marked with the private access modifier. Even if you have a method in the subclass with the same method name and arguments as a private method in the superclass it knows nothing of that method as it can't see it and is just a normal non-overriding method
  • You cannot override a method marked with the static modifier as overridden methods pertain to instance methods and not the class. In fact if you use the same static method and parameters in a subclass as a static method in a superclass this is known as method hiding and is discussed in Static Overrides?.

There are other rules regarding exceptions declarations when using overrides and these are discussed in the Flow Control section when we look at Overridden Methods & Exceptions.

Hopefully you're getting a feel for how inheritance works now and how we can build up an inheritance heirarchy to avoid duplication and streamline more specific objects.

Preventing Inheritance/Overridinggo to top of page Top

There might be a scenario whereby, you need to stop a class from being inherited. We can stop inheritance occurring by using the final keyword in the class definition:


/*
  A final Class
*/ 
public final class A {

}
/*
  B Class
*/ 
public class B extends A {

}

run extinding final test

The above screenshot shows the result of trying to compile class B.

On a similar note there might be a situation whereby, you need to stop a method from being overridden. We can stop this happening by using the final keyword in the method definition:


/*
  A Class
*/ 
public class A {

    final void aMethod () {
        System.out.println("Marked final so we can't override this method.");
    }   
}
/*
  B Class
*/ 
public class B extends A {

    void aMethod () {
        System.out.println("This won't work.");
    }   
}

run extending final test

The above screenshot shows the result of trying to compile class B.

You can also use the final keyword to create final local variables, final instance variables, within parameter lists and for creating java constants.

Lesson 2 Complete

In this lesson we introduced the OO concept of Inheritance, what it means and how we start to use it.

What's Next?

We continue our investigation of inheritance and conceptualize where our objects fit into the hierarchy.

go to home page Homepage go to top of page Top