Java Overriding
Java - Method Overriding
Section titled “Java - Method Overriding”Method overriding is a fundamental concept in object-oriented programming (OOP) and a key feature of polymorphism in Java. It allows a subclass (child class) to provide a specific implementation for a method that is already defined in its superclass (parent class).
When a subclass overrides a method, it essentially replaces the inherited implementation with its own version. This enables objects of the subclass to exhibit behavior specific to their type, even when referred to by a variable of the superclass type.
Key Benefits:
Section titled “Key Benefits:”- Specialized Behavior: Allows subclasses to define behavior tailored to their specific needs while adhering to the contract defined by the superclass method.
- Runtime Polymorphism: Enables the Java Virtual Machine (JVM) to determine which method version (superclass’s or subclass’s) to execute at runtime, based on the actual object type, not the reference variable type.
Example: Overriding a displayInfo Method
Section titled “Example: Overriding a displayInfo Method”Consider a Vehicle superclass and a Car subclass.
// Superclassclass Vehicle { String brand;
public Vehicle(String brand) { this.brand = brand; }
public void displayInfo() { System.out.println("Vehicle Brand: " + brand); }
public void startEngine() { System.out.println("Vehicle engine starting..."); }}
// Subclassclass Car extends Vehicle { int numberOfDoors;
public Car(String brand, int doors) { super(brand); // Call the superclass constructor this.numberOfDoors = doors; }
// --- Overriding the displayInfo method --- @Override // Annotation to ensure correct overriding (Recommended!) public void displayInfo() { System.out.println("Car Brand: " + brand + ", Doors: " + numberOfDoors); }
// Car-specific method public void honk() { System.out.println("Car honking: Beep beep!"); }}
public class TestVehicle { public static void main(String[] args) { Vehicle genericVehicle = new Vehicle("Generic"); Vehicle myCar = new Car("Toyota", 4); // Vehicle reference, Car object Car anotherCar = new Car("Honda", 2);
System.out.println("--- Calling displayInfo() ---"); genericVehicle.displayInfo(); // Calls Vehicle's version myCar.displayInfo(); // Calls Car's overridden version (Runtime Polymorphism) anotherCar.displayInfo(); // Calls Car's overridden version
System.out.println("\n--- Calling startEngine() --- (Inherited)"); genericVehicle.startEngine(); myCar.startEngine(); // Inherited from Vehicle anotherCar.startEngine();
System.out.println("\n--- Calling car-specific method --- "); // myCar.honk(); // Compile Error! 'myCar' is Vehicle type, doesn't know 'honk()' anotherCar.honk(); // Works fine, 'anotherCar' is Car type
// To call honk() on myCar, you need to cast: if (myCar instanceof Car) { // Check type before casting ((Car) myCar).honk(); } }}Output:
--- Calling displayInfo() ---Vehicle Brand: GenericCar Brand: Toyota, Doors: 4Car Brand: Honda, Doors: 2
--- Calling startEngine() --- (Inherited)Vehicle engine starting...Vehicle engine starting...Vehicle engine starting...
--- Calling car-specific method ---Car honking: Beep beep!Car honking: Beep beep!Explanation:
Section titled “Explanation:”- The
CarclassextendsVehicle, inheriting its fields and methods. Carprovides its owndisplayInfomethod, marked with@Override. This version prints car-specific details.- When
myCar.displayInfo()is called, even thoughmyCaris declared as typeVehicle, the JVM determines at runtime that the actual object is aCar. Therefore, it executes the overriddendisplayInfomethod from theCarclass. startEngine()is not overridden, so bothgenericVehicleandmyCaruse the implementation inherited fromVehicle.- The
honk()method exists only inCar. You cannot call it directly on aVehiclereference (myCar) without casting, because the compiler only knows about methods defined in theVehicleclass (or its superclasses).
The @Override Annotation
Section titled “The @Override Annotation”It is highly recommended to use the @Override annotation whenever you intend to override a superclass method.
Benefits:
Section titled “Benefits:”- Compile-Time Check: The compiler verifies that the annotated method actually overrides a method from a superclass or implements a method from an interface. If you make a mistake (e.g., misspell the method name, use incorrect parameters), you’ll get a compile-time error instead of a subtle runtime bug.
- Readability: Clearly indicates the programmer’s intent to override, making the code easier to understand.
Rules for Method Overriding
Section titled “Rules for Method Overriding”To correctly override a method, the following rules must be followed:
- Method Signature: The overriding method in the subclass must have the exact same name and parameter list (number, type, and order of parameters) as the method in the superclass.
- Return Type: The return type must be the same as, or a subtype of (covariant return type), the return type declared in the superclass method. (e.g., If superclass returns
Vehicle, subclass can returnCar). - Access Modifier: The access level of the overriding method cannot be more restrictive than the overridden method’s access level. (e.g., If superclass method is
public, subclass method cannot beprotectedorprivate. If superclass isprotected, subclass can beprotectedorpublic). finalMethods: Methods declaredfinalin the superclass cannot be overridden.staticMethods: Methods declaredstaticcannot be overridden (they belong to the class, not instances). If a subclass declares a static method with the same signature, it’s called method hiding, not overriding.privateMethods: Methods declaredprivateare not inherited and thus cannot be overridden.- Constructors: Constructors are not inherited and cannot be overridden.
- Exceptions: The overriding method can throw:
-
- Any unchecked exceptions (subclasses of
RuntimeExceptionorError), regardless of what the overridden method throws.
- Any unchecked exceptions (subclasses of
-
- The same checked exceptions (subclasses of
Exceptionbut notRuntimeException) as the overridden method.
- The same checked exceptions (subclasses of
-
- Subclasses of the checked exceptions thrown by the overridden method.
-
- Fewer checked exceptions than the overridden method, or no checked exceptions at all.
-
- It cannot throw new or broader checked exceptions than those declared by the overridden method.
Using the super Keyword
Section titled “Using the super Keyword”Sometimes, within an overriding method, you might want to execute the original implementation from the superclass before adding the subclass-specific behavior. You can achieve this using the super keyword.
super.methodName() calls the superclass’s version of the method.
Example:
Section titled “Example:”class Animal { public void makeSound() { System.out.println("Animal makes a sound"); }}
class Dog extends Animal { @Override public void makeSound() { super.makeSound(); // Call the Animal's makeSound() method first System.out.println("Dog barks: Woof woof!"); // Add Dog-specific behavior }}
public class TestSuper { public static void main(String[] args) { Animal myDog = new Dog(); myDog.makeSound(); }}Output:
Animal makes a soundDog barks: Woof woof!Overriding vs. Overloading
Section titled “Overriding vs. Overloading”Don’t confuse overriding with overloading:
| Feature | Method Overriding | Method Overloading |
|---|---|---|
| Purpose | Provide specific implementation in subclass for an inherited method. | Provide multiple methods with the same name but different parameters within the same class. |
| Method Signature | Same name, same parameter list. | Same name, different parameter list (number, type, or order). |
| Relationship | Occurs between superclass and subclass (inheritance). | Occurs within the same class. |
| Return Type | Can be same or covariant. | Can be different (return type alone doesn’t distinguish). |
| Polymorphism | Runtime polymorphism (dynamic dispatch). | Compile-time polymorphism (static binding). |
| Example | Car.displayInfo() overrides Vehicle.displayInfo(). | Calculator.add(int, int) and Calculator.add(double, double). |
What’s Next?
Section titled “What’s Next?”Method overriding is a cornerstone of polymorphism. The next chapter, ‘Java Polymorphism’, will explore this concept in more detail, showing how overriding enables flexible and extensible object-oriented designs.