22
DecOverriding In Java
Understanding Overriding in Java
Understanding Overriding in Java is a fundamental concept in Java's object-oriented programming. It allows a subclass to give a specific implementation of a method that is already specified in its parent class, which causes dynamic method dispatch. This guarantees the most relevant procedure is executed at runtime, hence increasing flexibility and code reuse.
In this Java Tutorial, we will look at What is Overriding in Java? And When to Apply Overriding in Java? We will also look at Rules for Java Method Overriding. So, let us start with "What is Overriding?".
Become a certified full stack developer with our expert-led Java Full Stack Developer Certification Training. Enroll today!
What is Overriding?
- Overriding in Java allows a subclass to replace a method specified in its parent class with its variant.
- This means that when you call the method on a subclass object, the subclass code of the method is used rather than the parent class code.
- For example, Consider a Vehicle class having a StartEngine function. If your Car class extends Vehicle, it can override the startEngine function to start the engine in a way that is specific to vehicles.
Example of Method Overriding in Java
Consider a superclass called Vehicle and its subclass Car. The Vehicle class has a method called start(), which is overridden by the Car class to give a more particular implementation.
Example
class Vehicle {
void start() {
System.out.println("The vehicle starts");
}
}
class Car extends Vehicle {
@Override
void start() {
System.out.println("The car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: The car starts with a key
}
}
Output
The car starts with a key
Explanation
In this example, the Car
class overrides the start()
method from the Vehicle
class. When start()
is called on a Vehicle
reference pointing to a Car
object, the overridden method in the Car
class is executed, resulting in the output "The car starts with a key."
Why Overriding in Java is Useful?
- Overridden methods in Java are a type of polymorphism that allows you to have a single method that can function differently depending on the object on which it is called.
- One of the most significant advantages of object-oriented programming is the ability to reuse and strengthen code. Dynamic process execution allows you to utilize existing code libraries to call methods on new class objects without having to recompile your code while maintaining a clean and simple interface.
- Overridden methods allow you to call a method on any object from a derived class without knowing the specifics of the modified superclass.
When to Apply Overriding in Java?
- Identifying parent and child classes forms a hierarchy that helps make the most of polymorphism.
- A well-designed parent class contains everything the child class needs to access directly and also outlines which methods the child class must implement on its own.
- This setup allows the child class to use its own methods while maintaining a consistent interface.
- By combining inheritance and overridden methods, the parent class defines the general structure of the methods that all its child classes will use.
Rules for Java Method Overriding
- The method name should be common and match that of the parent class.
- The method's signature (parameter list, return type) must be the same as the parent class.
- Classes must have an inheritance relationship between them.
- All abstract methods from the parent class should be overridden in the child class.
- If the methods are defined as static or final, they cannot be overridden.
Let's understand them with a simple examples:
1. Overriding and Access Modifiers
- The access modifier for an overriding method can give more access but not less than the method it overrides.
- For example, if a superclass has a protected method, the subclass can make it public but not private. Trying to make it private would cause a compile-time error.
Example
class Vehicle {
public void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
@Override
public void start() { // Must be public
System.out.println("Car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Car starts with a key
}
}
Output
Car starts with a key
Explanation
- The
Vehicle
class has astart()
method which ispublic
. - The
Car
class extendsVehicle
and overrides thestart()
method, ensuring it is alsopublic
. - When the
start()
the method is invoked on aCar
the object referenced as aVehicle
, the overridden method in theCar
class is executed, demonstrating polymorphism in Java.
2. Final methods can not be overridden
A method declared final cannot be overridden. The final keyword prevents the method's behavior from being modified in subclasses.Example
class Vehicle {
public final void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
// This would cause a compile-time error if uncommented
// @Override
// public void start() {
// System.out.println("Car starts with a key");
// }
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Vehicle starts
}
}
Output
Vehicle starts
Explanation
- The
Vehicle
class has astart()
method marked asfinal
, which means it cannot be overridden by any subclasses. - In the
Car
class, attempting to override this method would result in a compile-time error. - When the
start()
a method is called on aCar
object (referenced as aVehicle
), thestart()
method from theVehicle
class is executed, demonstrating that thefinal
method cannot be overridden.
3. Static methods can not be overridden
Superclass Instance Method | Superclass Static Method | |
Subclass Instance Method | Overrides | Causes a compile-time error |
Subclass Static Method | Causes a compile-time error | Hides |
Example
class Vehicle {
public static void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
public static void start() { // Hides the Vehicle's start method
System.out.println("Car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle.start(); // Outputs: Vehicle starts
Car.start(); // Outputs: Car starts with a key
}
}
Output
Vehicle starts
Car starts with a key
Explanation
- The
Vehicle
the class has a staticstart()
method, which is hidden by theCar
class’s staticstart()
method. - When
Vehicle.start()
is called, it invokes thestart()
method from theVehicle
class. Similarly, callingCar.start()
invokes thestart()
method from theCar
class. - This demonstrates method hiding in Java, where static methods are bound at compile time rather than runtime.
4. Private Methods Cannot Be Overridden
Example
class Vehicle {
private void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
private void start() { // Not overriding
System.out.println("Car starts with a key");
}
public void showStart() {
start(); // Calls Car's private start method
}
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
myCar.showStart(); // Outputs: Car starts with a key
}
}
Output
Car starts with a key
Explanation
- The
Vehicle
class defines a privatestart()
method, and theCar
class defines its own privatestart()
method. - Since
start()
inCar
is private, it does not override thestart()
method inVehicle
. - The
showStart()
method inCar
calls the privatestart()
method defined inCar
, so whenshowStart()
is invoked, it prints, "Car starts with a key."
5. The Overriding Method Must Have the Same Return Type (or Subtype)
From Java 5.0 onwards, alternative return types can be used for an overriding method in the child class, but the child's return type must be a subtype of the parent's return type. This behavior is referred to as covariant return type.
Example
class Vehicle {
public Vehicle start() {
System.out.println("Vehicle starts");
return new Vehicle();
}
}
class Car extends Vehicle {
@Override
public Car start() { // Covariant return type
System.out.println("Car starts with a key");
return new Car();
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Car starts with a key
}
}
Output
Car starts with a key
Explanation
- The
Vehicle
the class has a methodstart()
that returns aVehicle
instance. - The
Car
the class overrides this method with a return type ofCar
, which is a subclass ofVehicle
. - This is an example of covariant return types, where the overriding method can return a type that is a subtype of the return type of the method in the superclass.
- When
start()
is called on aVehicle
reference pointing to aCar
object, it executes thestart()
method from theCar
class, resulting in "Car starts with a key" being printed.
6. Invoking Overridden Methods from Subclass
You can call an overridden method in the subclass using the super keyword, which refers to the superclass’s implementation.
Example
class Vehicle {
public void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
@Override
public void start() {
super.start(); // Calls Vehicle's start
System.out.println("Car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Vehicle starts followed by Car starts with a key
}
}
Output
Vehicle starts
Car starts with a key
Explanation
- The
Car
class overrides thestart()
method from theVehicle
class. - Within the
start()
method inCar
, it first callssuper.start()
to invoke thestart()
method of the superclass (Vehicle
), which prints "Vehicle starts". - Then, it prints, "Car starts with a key."
- When
start()
is called on aVehicle
reference pointing to aCar
object, it prints both messages, with "Vehicle starts" followed by "Car starts with a key".
Overriding and Constructor
Example
class Vehicle {
Vehicle() {
System.out.println("Vehicle constructor");
}
}
class Car extends Vehicle {
Car() {
System.out.println("Car constructor");
}
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car(); // Outputs: Vehicle constructor followed by Car constructor
}
}
Output
Vehicle constructor
Car constructor
Explanation
- When creating an instance of the
Car
class, the constructor of its superclass (Vehicle
) is invoked first before the constructor of theCar
class. - This is because, in Java, the constructor of the superclass is always called before the subclass constructor.
- As a result, "Vehicle constructor" is printed first, followed by "Car constructor."
Overriding and Exception Handling
Rule #1: Exception Types
The overriding method cannot throw broader checked exceptions than those specified in the superclass method. It can generate the same or narrower exceptions.Example
import java.io.IOException;
class Vehicle {
public void start() throws Exception {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
@Override
public void start() throws IOException { // Narrower exception
System.out.println("Car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
try {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Car starts with a key
} catch (Exception e) {
System.out.println("Exception caught: " + e);
}
}
}
Output
Car starts with a key
Explanation
- In this example, the
Car
class overrides thestart()
method of theVehicle
class. - The overriding method in
Car
throws a narrower exception type (IOException
) compared to the method inVehicle
which throws a generalException
. - This is allowed in Java because a subclass method can only throw exceptions that are subclasses of the exceptions thrown by the superclass method.
- When
start()
is called on aVehicle
reference pointing to aCar
object, it executes the overridden method inCar
, resulting in "Car starts with a key" being printed.
Rule #2: Exception Handling in Subclass
If the superclass method does not declare any checked exceptions, the subclass method cannot declare any checked exceptions.
Example
import java.io.IOException;
class Vehicle {
public void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
@Override
public void start() { // No checked exceptions allowed
System.out.println("Car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Car starts with a key
}
}
Output
Car starts with a key
Explanation
- In this example, the
Car
class overrides thestart()
method of theVehicle
class. - The overriding method in
Car
does not declare any checked exceptions, which is allowed as the superclass method does not throw any checked exceptions either. - When
start()
is called on aVehicle
reference pointing to aCar
object, it executes the overridden method inCar
, resulting in "Car starts with a key" being printed.
Overriding and Abstract Method
Example
abstract class Vehicle {
abstract void start();
}
class Car extends Vehicle {
@Override
void start() {
System.out.println("Car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Car starts with a key
}
}
Output
Car starts with a key
Explanation
- In this example, the
Vehicle
class is abstract and defines an abstract methodstart()
. - The
Car
class extendsVehicle
and provides an implementation for thestart()
method. - When
start()
is called on aVehicle
reference pointing to aCar
object, it executes the overridden method inCar
, resulting in "Car starts with a key" being printed.
Overriding and Synchronized/strictfp Method
Methods marked with synchronized or strictfp can be overridden, but these attributes will not be retained until explicitly expressed in the subclass.Example
class Vehicle {
public synchronized void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
@Override
public void start() { // Not synchronized
System.out.println("Car starts with a key");
}
}
public class Main {
public static void main(String[] args) {
Vehicle myCar = new Car();
myCar.start(); // Outputs: Car starts with a key
}
}
Output
Car starts with a key
Explanation
- In this example, the
Vehicle
the class has a synchronizedstart()
method, which ensures that only one thread can execute this method at a time. - However, the
Car
class overrides thestart()
method without thesynchronized
keyword. - When
start()
is called on aVehicle
reference pointing to aCar
object, it executes the overridden method inCar
, which is not synchronized. - Therefore, "Car starts with a key" is printed.
Method Overriding vs. Method Overloading
- Overloading and Overriding are two basic ideas that are different in several various ways in Java.
- Overloading is similar to a car's acceleration function, which can be utilized in a variety of ways.
- For example, you can accelerate by pushing the gas pedal with varying degrees of force (the same procedure, different parameters).
- The car's behavior changes depending on how you utilize the pedal.
- Overriding is similar to a car's start function, in which different types of cars (for example, a petrol car and an electric car) have different ways to start, despite the fact that the operation is the same.