In Java, inheritance is a fundamental concept of Object-Oriented Programming (OOP). It is a mechanism that allows a subclass to inherit all the attributes (fields) and behaviors (methods) of a superclass. The purpose of inheritance is to create new classes that can reuse and extend the functionality of existing classes. The new class will inherit all the fields and methods from the existing class (except those declared with the private modifier), and it may also define its own fields and methods.
In object-oriented programming, inheritance involves a parent class (superclass) that serves as the basis for a new child class (subclass). Just like in real life, a child often inherits various characteristics from their parent.
Note: Note that a class can inherit from only one parent class, but it can have an unlimited number of child classes, also known as subclasses.
Inheritance in Java is implemented using the “extends” keyword, which allows a subclass to inherit the properties and methods of a superclass. The syntax for creating a subclass that extends a superclass looks like this:
public class SubClass extends SuperClass { // fields // methods }
Inheritance Code Example in Java
Let’s say we have classes Vehicle and Car. Since a car is a vehicle in real life, we can create a class hierarchy where the Car class extends the Vehicle class, inheriting all the properties and behaviors of the Vehicle class and adding its own specific properties and methods.
class Vehicle { private String brand; // a superclass constructor that can't be inherited public Vehicle(String brand) { this.brand = brand; } public void printBrand() { System.out.println("Brand is: " + brand); } // overriding the toString() method of a superclass Object public String toString() { return "This is a " + brand; } } class Car extends Vehicle { // car has its own attributes declared private int numberOfSeats; private String colour; //constructor of the subclass public Car(String model, int numberOfSeats, String colour) { super(model); // call the constructor of the superclass to set the brand field this.numberOfSeats = numberOfSeats; this.colour = colour; } // Method which returns custom string for the Car public String printCar() { return super.toString() + " with a number of seats " + numberOfSeats + " and with colour " + colour; } } public class Test { public static void main(String[] args) { Car car = new Car("Ford", 5, "blue"); car.printBrand(); // calling the inherited method System.out.println(car.printCar()); } }
Brand is: Ford This is a Ford with a number of seats 5 and with colour blue
In the code example given above, the Car class inherited the printBrand()
method from its superclass Vehicle. This means that even though the method was not declared in the Car class, it was still available for use because it was inherited from the superclass.
Notes:
- The constructor of a superclass can only be called explicitly from the subclass constructor using the
super
keyword. This ensures that the superclass constructor is called before the subclass constructor and the superclass fields are initialized before the subclass fields. - All classes in Java extend the
java.lang.Object
class by default. This ensures that the classes we define inherit members of theObject
class. TheObject
class is the root of the class hierarchy in Java and provides a set of methods that are common to all objects, such asequals()
,toString()
, andhashCode()
. These methods can be overridden in your own classes to provide custom behavior.
Inheriting Constructors
Like fields and methods, a subclass can also inherit constructors from its superclass. When a subclass object is created, the constructor of its superclass is called automatically before the subclass constructor. This ensures that the superclass fields are initialized before the subclass fields.
If the superclass has a constructor that takes arguments, the subclass constructor must also take the same arguments and call the superclass constructor using the super
keyword, which passes the arguments to the superclass constructor. If the superclass has multiple constructors, the subclass must explicitly call one of them using the super
keyword. If the superclass has no constructor defined, a default constructor is provided automatically, which can be called implicitly by the subclass constructor.
Here’s an example of a subclass that inherits a constructor from its superclass:
class Vehicle { private String brand; public Vehicle(String brand) { this.brand = brand; } } class Car extends Vehicle { private int numberOfSeats; public Car(String brand, int numberOfSeats) { super(brand); this.numberOfSeats = numberOfSeats; } }
In this example, the Vehicle
class has a constructor that takes a String
argument brand
, which is used to initialize the brand
field. The Car
class extends Vehicle
and has an additional field numberOfSeats
. The Car
class constructor takes two arguments, a String
argument brand
and an int
argument numberOfSeats
. The super(brand)
statement in the Car
constructor calls the Vehicle
constructor with the brand
argument, which initializes the brand
field of the Car
object. Then the numberOfSeats
field of the Car
object is initialized with the numberOfSeats
argument.
Overriding Methods
When a subclass inherits a method from its superclass, it can override that method to provide its own implementation. To override a method, the subclass method must have the same name, return type, and parameter list as the superclass method. The @Override
annotation can be used to indicate that a method is intended to override a superclass method.
Here’s an example of a subclass that overrides a method from its superclass:
class Animal { public void makeSound() { System.out.println("Animal is making a sound"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("Dog is barking"); } }
In this example, the Animal
class has a method makeSound()
that prints a message to the console. The Dog
class extends Animal
and overrides the makeSound()
method to print a different message.
Access Modifiers
Inheritance affects the access modifiers of fields and methods in a class. In general, a subclass can access public and protected members of its superclass, but not private members. If a field or method in a superclass is marked as private, it cannot be accessed by a subclass. If a field or method is marked as public or protected, it can be accessed by a subclass.
Here’s an example of a subclass that accesses a public field and a protected method of its superclass:
class Person { protected String name; public void sayHello() { System.out.println("Hello, my name is " + name); } } class Student extends Person { public Student(String name) { this.name = name; } public void introduce() { System.out.println("I am a student named " + name); } }
In this example, the Person
class has a protected field name
and a public method sayHello()
that uses the name
field. The Student
class extends Person
and has a constructor that sets the name
field. The Student
class also has a method introduce()
that prints a message to the console using the name
field.
Abstract Classes and Interfaces
In addition to regular classes, Java also supports abstract classes and interfaces, which can be used to define common behavior for a group of related classes. An abstract class is a class that cannot be instantiated directly and can contain abstract methods, which are declared but not implemented. An interface is a collection of abstract methods and constant fields, which can be implemented by any class that wants to conform to the interface.
Here’s an example of an abstract class and an interface:
abstract class Shape { protected double area; public abstract void calculateArea(); } interface Drawable { void draw(); } class Circle extends Shape implements Drawable { private double radius; public Circle(double radius) { this.radius = radius; } @Override public void calculateArea() { area = Math.PI * radius * radius; } @Override public void draw() { System.out.println("Drawing a circle"); } }
In this example, the Shape
class is an abstract class that has a protected field area
and an abstract method calculateArea()
. The Drawable
interface has a single method draw()
. The Circle
class extends Shape
and implements Drawable
. It has a constructor that sets the radius
field and overrides the calculateArea()
method to calculate the area of a circle. It also overrides the draw()
method to print a message to the console.
Conclusion
In conclusion, inheritance is a powerful feature of object-oriented programming in Java that allows us to create a hierarchy of classes with shared attributes and behaviors. By using inheritance, we can avoid code duplication and write more efficient and maintainable code. In this tutorial, we covered the basics of inheritance in Java, including how to create a subclass, how to override methods, and how to use the super keyword. We also learned how constructors work in inheritance and how to call the constructor of a superclass from a subclass.
If you want to learn more about Java programming, make sure to check out Java Tutorials for Beginners page.