Tech and Media Labs
This site uses cookies to improve the user experience.




Java Inheritance

Jakob Jenkov
Last update: 2015-09-04

Java inheritance refers to the ability in Java for one class to inherit from another class. In Java this is also called extending a class. One class can extend another class and thereby inherit from that class.

When one class inherits from another class in Java, the two classes take on certain roles. The class that extends (inherits from another class) is the subclass and the class that is being extended (the class being inherited from) is the superclass . In other words, the subclass extends the superclass. Or, the subclass inherits from the superclass.

Another commonly used term for inheritance is specialization and generalization. A subclass is a specialization of a superclass, and a superclass is a generalization of one or more subclasses.

Inheritance is a Method of Code Reuse

Inheritance can be an effective method to share code between classes that have some traits in common, yet allowing the classes to have some parts that are different.

Here is diagram illustrating a class called Vehicle, which has two subclasses called Car and Truck.

The class Car and Truck inherits from the class Vehicle.
The class Car and Truck inherits from the class Vehicle.

The Vehicle class is the superclass of Car and Truck. Car and Truck are subclasses of Vehicle. The Vehicle class can contain those fields and methods that all Vehicles need (e.g. a license plate, owner etc.), whereas Car and Truck can contain the fields and methods that are specific to Cars and Trucks.

Note: Some people will claim that inheritance is a way to categorize your classes based on what they are. A Car is a Vehicle. A Truck is a Vehicle. In practice, however, that is not how you determine which superclasses and subclasses your application needs to have. This is typically determined by how you need to work with them in the application.

For instance, do you need to refer to Car and Truck objects as Vehicle objects? Do you need to process both Car and Truck objects uniformly? Then it makes sense to have a common Vehicle superclass for the two classes. If you never process Car and Truck objects in the same way, there is no point in having a common superclass for them, except perhaps to share code between them (to avoid writing duplicate code).

Class Hierarchies

Superclasses and subclasses form an inheritance structure which is also called a class hierarchy. At the top of the class hierarchy you have the superclasses. At the bottom of the class hierarchy you have the subclasses.

A class hierarchy may have multiple levels, meaning multiple levels of superclasses and subclasses. A subclass may itself be a superclass of other subclasses etc.

Java Inheritance Basics

When a class inherits from a superclass, it inherits parts of the superclass methods and fields. The subclass can also override (redefine) the inherited methods. Fields cannot be overridden, but can be "shadowed" in subclasses. How all this works is covered later in this text.

What is Inherited?

When a subclass extends a superclass in Java, all protected and public fields and methods of the superclass are inherited by the subclass. By inherited is meant that these fields and methods are part of of the subclass, as if the subclass had declared them itself. protected and public fields can be called and referenced just like the methods declared directly in the subclass.

Fields and methods with default (package) access modifiers can be accessed by subclasses only if the subclass is located in the same package as the superclass. Private fields and methods of the superclass can never be referenced directly by subclasses. They can, however, be referenced indirectly via methods reachable from the subclass (e.g default (package), protected and public methods).

Constructors are not inherited by subclasses, but a subclass constructor must call a constructor in the superclass. This will be explained in detail in a later section.

Java Only Supports Singular Inheritance

The Java inheritance mechanism only allows a Java class to inherit from a single superclass (singular inheritance). In some programming languages, like C++, it is possible for a subclass to inherit from multiple superclasses (multiple inheritance). Since multiple inheritance can create some weird problems, if e.g. the superclasses contain methods with the same names and parameters, multiple inheritance was left out in Java.

Declaring Inheritance in Java

In Java inheritance is declared using the extends keyword. You declare that one class extends another class by using the extends keyword in the class definition. Here is Java inheritance example using the extends keyword:

public class Vehicle {
    protected String licensePlate = null;

    public void setLicensePlate(String license) {
        this.licensePlate = license;
    }
}
public class Car extends Vehicle {
    int numberOfSeats = 0;

    public String getNumberOfSeats() {
        return this.numberOfSeats;
    }
}

The Car class in this example extends the Vehicle class, meaning the Car class inherits from the Vehicle class.

Because the Car class extends the Vehicle class, the protected field licensePlate from the Vehicle class is inherited by the Car class. When the licensePlate field is inherited, it is accessible inside a Car instance.

The licensePlate field is not actually being referenced from the Car class in the code above, but it could if we wanted to. Here is an example that shows how that could look:

public class Car extends Vehicle {
    int numberOfSeats = 0;

    public String getNumberOfSeats() {
        return this.numberOfSeats;
    }

    public String getLicensePlate() {
        return this.licensePlate;
    }
}

The referencing happens inside the getLicensePlate() method.

In many cases it would have made sense to place the getLicensePlate() method in the Vehicle class where the licensePlate field is located. I just placed the getLicensePlate() method in the Car class to show that it is possible.

Inheritance and Type Casting

It is possible to reference a subclass as an instance of one of its superclasses. For instance, using the class definitions from the example in the previous section it is possible to reference an instance of the Car class as an instance of the Vehicle class. Because the Car class extends (inherits from) the Vehicle class, it is also said to be a Vehicle.

Here is a Java code example:

Car     car     = new Car();
Vehicle vehicle = car;

First a Car instance is created. Second, the Car instance is assigned to a variable of type Vehicle. Now the Vehicle variable (reference) points to the Car instance. This is possible because the Car class inherits from the Vehicle class.

As you can see, it is possible to use an instance of some subclass as if it were an instance of its superclass. That way, you don't need to know exactly what subclass the object is an instance of. You could treat e.g. both Truck and Car instances as Vehicle instances.

The process of referencing an object of class as a different type than the class itself is called type casting. You cast an object from one type to another.

Upcasting and Downcasting

You can always cast an object of a subclass to one of its superclasses. This is referred to as upcasting (from a subclass type to a superclass type).

It may also be possible to cast an object from a superclass type to a subclass type, but only if the object really is an instance of that subclass (or an instance of a subclass of that subclass). This is referred to as downcasting (from a superclass type to a subclass type). Thus, this example of downcasting is valid:

Car     car     = new Car();

// upcast to Vehicle
Vehicle vehicle = car;

// downcast to car again
Car     car2    =  (Car) vehicle;

However, the following downcast example is not valid. The Java compiler will accept it, but at runtime when this code is executed the code will throw a ClassCastException.

Truck   truck   = new Truck();

// upcast to Vehicle
Vehicle vehicle = truck;

// downcast to car again
Car     car     =  (Car) vehicle;

The Truck object can be upcast to a Vehicle object, but it cannot be downcast to a Car object later. This will result in a ClassCastException.

Overriding Methods

In a subclass you can override (redefine) methods defined in the superclass. Here is a Java method override example:

public class Vehicle {

    String licensePlate = null;

    public void setLicensePlate(String licensePlate) {
        this.licensePlate = licensePlate;
    }
}
public class Car extends Vehicle {

    public void setLicensePlate(String license) {
        this.licensePlate = license.toLowerCase();
    }

}

Notice how both the Vehicle class and the Car class defines a method called setLicensePlate(). Now, whenever the setLicensePlate() method is called on a Car object, it is the method defined in the Car class that is called. The method in the superclass is ignored.

To override a method the method signature in the subclass must be the same as in the superclass. That means that the method definition in the subclass must have exactly the same name and the same number and type of parameters, and the parameters must be listed in the exact same sequence as in the superclass. Otherwise the method in the subclass will be considered a separate method.

In Java you cannot override private methods from a superclass. If the superclass calls a private method internally from some other method, it will continue to call that method from the superclass, even if you create a private method in the subclass with the same signature.

The @override Annotation

If you override a method in a subclass, and the method is all of a sudden removed or renamed or have its signature changed in the superclass, the method in the subclass no longer overrides the method in the superclass. But how do you know? It would be nice if the compiler could tell you that the method being overridden no longer overrides a method in the superclass, right?

This is what the Java @override annotation is for. You place the Java @override annotation above the method that overrides a method in a superclass. Here is Java @override example:

public class Car extends Vehicle {

    @Override
    public void setLicensePlate(String license) {
        this.licensePlate = license.toLowerCase();
    }

}

Calling Superclass Methods

If you override a method in a subclass, but still need to call the method defined in the superclass, you can do so using the super reference, like this:

public class Car extends Vehicle {

    public void setLicensePlate(String license) {
        super.setLicensePlate(license);
    }

}

In the above code example the method setLicensePlate() in the Car class, calls the setLicensePlate() method in the Vehicle class.

You can call superclass implementations from any method in a subclass, like above. It does not have to be from the overridden method itself. For instance, you could also have called super.setLicensePlate() from a method in the Car class called updateLicensePlate() which does not override the setLicensePlate() method.

The instanceof Instruction

Java contains an instruction named instanceof. The instanceof instruction can determine whether a given object is an instance of some class. Here is a Java instanceof example:

Car car = new Car();

boolean isCar = car instanceof Car;

After this code has been executed the isCar variable will contain the value true.

The instanceof instruction can also be used determine if an object is a instance of a superclass of its class. Here is an instanceof example that checks if a Car object is an instance of Vehicle:

Car car = new Car();

boolean isVehicle = car instanceof Vehicle;

Assuming that the Car class extends (inherits from) the Vehicle class, the isVehicle variable will contain the value true after this code is executed. A Car object is also a Vehicle object because Car is a subclass of Vehicle.

As you can see, the instanceof instruction can be used to explore the inheritance hierarchy.

The variable type used with the instanceof instruction does not affect its outcome. Look at this instanceof example:

Car car = new Car();

Vehicle vehicle = car;

boolean isCar = vehicle instanceof Car;

Even though the vehicle variable is of type Vehicle, the object it ends up pointing to in this example is a Car object. Therefore the vehicle instanceof Car instruction will evaluate to true.

Here is the same instanceof example, but using a Truck object instead of a Car object:

Truck truck = new Truck();

Vehicle vehicle = truck;

boolean isCar = vehicle instanceof Car;

After executing this code the isCar will contain the value false. The Truck object is not a Car object.

Fields and Inheritance

As mentioned earlier, in Java fields cannot be overridden in a subclass. If you define a field in a subclass with the same name as a field in the superclass, the field in the subclass will hide (shadow) the field in the superclass. If the subclass tries to access the field, it will access the field in the subclass.

If, however, the subclass calls up into a method in the superclass, and that method accesses the field with the same name as in the subclass, it is the field in the superclass that is accessed.

Here is Java inheritance example that illustrates how fields in subclasses shadow (hides) fields in superclasses:

public class Vehicle {

    String licensePlate = null;

    public void setLicensePlate(String licensePlate) {
        this.licensePlate = licensePlate;
    }

    public String getLicensePlate() {
        return licensePlate;
    }
}
public class Car extends Vehicle {

    protected String licensePlate = null;

    @Override
    public void setLicensePlate(String license) {
        super.setLicensePlate(license);
    }

    @Override
    public String getLicensePlate() {
        return super.getLicensePlate();
    }

    public void updateLicensePlate(String license){
        this.licensePlate = license;
    }
}

Notice how both classes have a licensePlate field defined.

Both the Vehicle class and Car class has the methods setLicensePlate() and getLicensePlate(). The methods in the Car class calls the corresponding methods in the Vehicle class. The result is, that eventually both set of methods access the licensePlate field in the Vehicle class.

The updateLicensePlate() method in the Car class however, accesses the licensePlate field directly. Thus, it accesses the licensePlate field of the Car class. Therefore, you will not get the same result if you call setLicensePlate() as when you call the updateLicense() method.

Look at the following lines of Java code:

Car car = new Car();

car.setLicensePlate("123");
car.updateLicensePlate("abc");

System.out.println("license plate: "
        + car.getLicensePlate());

This Java code will print out the text 123.

The updateLicensePlate() method sets the license plate value on the licensePlate field in the Car class. The getLicensePlate() method, however, returns the value of the licensePlate field in the Vehicle class. Therefore, the value 123 which is set as value for the licensePlate field in the Vehicle class via the setLicensePlate() method, is what is printed out.

Constructors and Inheritance

The Java inheritance mechanism does not include constructors. In other words, constructors of a superclass are not inherited by subclasses. Subclasses can still call the constructors in the superclass using the super() contruct. In fact, a subclass constructor is required to call one of the constructors in the superclass as the very first action inside the constructor body. Here is how that looks:

public class Vehicle {

    public Vehicle() {
    }
}
public class Car extends Vehicle{

    public Car() {
        super();

        //perform other initialization here
    }
}

Notice the call to super() inside the Car constructor. This super() call executes the constructor in the Vehicle class.

You may have seen Java classes where the subclass constructors did not seem to call the constructors in the superclass. Maybe the superclass did not even have a constructor. However, the subclass constructors have still called superclass constructors in those case. You just could not see it. Let me explain why:

If a class does not have any explicit constructor defined, the Java compiler inserts an implicit no-arg constructor. Thus, a class always has a constructor. Therefore the following version of Vehicle is equivalent to the version shown just above:

public class Vehicle {
}

Second, if a constructor does not explicitly call a constructor in the superclass, the Java compiler inserts an implicit call to the no-arg constructor in the superclass. That means that the following version of the Car class is actually equivalent to the version shown earlier:

public class Car extends Vehicle{

    public Car() {
    }
}

In fact, since the constructor is now empty, we could leave it out and the Java compiler would insert it, and insert an implicit call to the no-arg constructor in the superclass. This is how the two classes would look then:

public class Vehicle {
}
public class Car extends Vehicle{
}

Even though no constructors are declared in these two classes, they both get a no-arg constructor, and the no-arg constructor in the Car class will call the no-arg constructor in the Vehicle class.

If the Vehicle class did not have a no-arg constructor, but had another constructor which takes parameters, the Java compiler would complain. The Car class would then be required to declare a constructor, and inside that constructor call the constructor in the Vehicle class.

Nested Classes and Inheritance

The same Java inheritance rules apply to nested classes. Nested classes which are declared private are not inherited. Nested classes with the default (package) access modifier are only accessible to subclasses if the subclass is located in the same package as the superclass. Nested classes with the protected or public access modifier are always inherited by subclasses.

Here is a nested class inheritance example:

class MyClass {

    class MyNestedClass {

    }
}
public class MySubclass extends MyClass {

    public static void main(String[] args) {
        MySubclass subclass = new MySubclass();

        MyNestedClass nested =  subclass.new MyNestedClass();
    }
}

Notice how it is possible to create an instance of the nested class MyNestedClass which is defined in the superclass (MyClass) via a reference to the subclass (MySubclass).

Final Classes and Inheritance

A class can be declared final. Here is now that looks:

public final class MyClass {

}

A final class cannot be extended. In other words, you cannot inherit from a final class in Java.

Abstract Classes and Inheritance

In Java a class can be declared abstract. I have explained abstract classes in more detail in my Java abstract classes tutorial.

An abstract class is a class that does not contain the full implementation of whatever the abstract class should do. Thus, it cannot be instantiated. In other words, you cannot create objects of an abstract class.

In Java abstract classes are intended to be extended to create a full implementation. Thus, it is fully possible to extend an abstract class. The Java inheritance rules are the same for abstract classes as for non-abstract classes.

Jakob Jenkov




Copyright  Jenkov Aps
Close TOC