Java Inheritance
- Inheritance is a Method of Code Reuse
- Class Hierarchies
- Java Inheritance Basics
- Declaring Inheritance in Java
- Inheritance and Type Casting
- Overriding Methods
- The instanceof Instruction
- Fields and Inheritance
- Constructors and Inheritance
- Nested Classes and Inheritance
- Final Classes and Inheritance
- Abstract Classes and Inheritance
Jakob Jenkov |
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 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.
| Tweet | |
Jakob Jenkov | |












