Introduction
Method Overriding occurs when a subclass provides a specific implementation of a method already defined in its parent class.
Basic Concept
class Parent {
void display() {
System.out.println("Parent display");
}
}
class Child extends Parent {
@Override // Annotation (optional but recommended)
void display() {
System.out.println("Child display");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Parent();
p.display(); // Parent display
Child c = new Child();
c.display(); // Child display (overridden)
}
}
Rules for Method Overriding
- Same method signature (name + parameters)
- Same or covariant return type
- Cannot reduce access (can increase)
- Cannot throw new checked exceptions
- Must use @Override annotation (recommended)
- Method must be inherited (not private)
- static methods cannot be overridden
- final methods cannot be overridden
Simple Example
class Animal {
void sound() {
System.out.println("Animal makes sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Animal();
a.sound(); // Animal makes sound
Dog d = new Dog();
d.sound(); // Dog barks
Cat c = new Cat();
c.sound(); // Cat meows
}
}
Using super to Call Parent Method
class Parent {
void display() {
System.out.println("Parent display");
}
}
class Child extends Parent {
@Override
void display() {
super.display(); // Call parent method first
System.out.println("Child display");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.display();
}
}
Output:
Parent display
Child display
Complete Example
class BankAccount {
protected double balance;
void deposit(double amount) {
balance += amount;
System.out.println("Deposited: " + amount);
System.out.println("Balance: " + balance);
}
void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
System.out.println("Withdrawn: " + amount);
} else {
System.out.println("Insufficient balance");
}
}
}
class SavingsAccount extends BankAccount {
private double minimumBalance = 1000;
@Override
void withdraw(double amount) {
if (balance - amount >= minimumBalance) {
super.withdraw(amount); // Call parent withdraw
} else {
System.out.println("Cannot withdraw. Minimum balance required: " + minimumBalance);
}
}
}
public class Main {
public static void main(String[] args) {
SavingsAccount acc = new SavingsAccount();
acc.deposit(5000);
acc.withdraw(3000); // Not allowed (below minimum)
acc.withdraw(2000); // Allowed
}
}
Access Modifier Rules
Can Increase Access:
class Parent {
protected void method() { } // protected
}
class Child extends Parent {
@Override
public void method() { } // ✓ OK: increased to public
}
Cannot Reduce Access:
class Parent {
public void method() { } // public
}
class Child extends Parent {
@Override
protected void method() { } // ✗ Error: reduced to protected
}
Return Type Rules
Same Return Type:
class Parent {
int getValue() {
return 10;
}
}
class Child extends Parent {
@Override
int getValue() { // ✓ Same return type
return 20;
}
}
Covariant Return Type:
class Animal { }
class Dog extends Animal { }
class Parent {
Animal getAnimal() {
return new Animal();
}
}
class Child extends Parent {
@Override
Dog getAnimal() { // ✓ Covariant return type (subclass)
return new Dog();
}
}
@Override Annotation
class Parent {
void display() { }
}
class Child extends Parent {
@Override // Recommended
void display() { } // Compiler checks if this actually overrides
}
Benefits:
- Compile-time check: Ensures method actually overrides
- Prevents typos: Catches spelling mistakes
- Documentation: Clear intent
Without @Override:
class Parent {
void display() { }
}
class Child extends Parent {
void Display() { } // Typo! This is a NEW method, not override
}
With @Override:
class Child extends Parent {
@Override
void Display() { } // ✗ Compiler error: method doesn't override
}
Static Methods Cannot Be Overridden
class Parent {
static void display() {
System.out.println("Parent static");
}
}
class Child extends Parent {
static void display() { // This is method HIDING, not overriding
System.out.println("Child static");
}
}
public class Main {
public static void main(String[] args) {
Parent.display(); // Parent static
Child.display(); // Child static
Parent p = new Child();
p.display(); // Parent static (not polymorphic)
}
}
Real-World Example
class Shape {
String color;
double area() {
return 0;
}
void display() {
System.out.println("Color: " + color);
System.out.println("Area: " + area());
}
}
class Circle extends Shape {
double radius;
Circle(String color, double radius) {
this.color = color;
this.radius = radius;
}
@Override
double area() {
return Math.PI * radius * radius;
}
}
class Rectangle extends Shape {
double length, width;
Rectangle(String color, double length, double width) {
this.color = color;
this.length = length;
this.width = width;
}
@Override
double area() {
return length * width;
}
}
public class Main {
public static void main(String[] args) {
Circle c = new Circle("Red", 5);
c.display();
System.out.println();
Rectangle r = new Rectangle("Blue", 4, 6);
r.display();
}
}
Overriding vs Overloading
| Overriding | Overloading |
|---|---|
| Same signature | Different parameters |
| Parent-child classes | Same class |
| Runtime (dynamic) | Compile-time (static) |
| Polymorphism | Flexibility |
| Uses inheritance | No inheritance needed |
| @Override annotation | No special annotation |
Runtime Polymorphism
class Animal {
void sound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Bark");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Meow");
}
}
public class Main {
public static void main(String[] args) {
Animal a; // Parent reference
a = new Dog();
a.sound(); // Bark (Dog's method)
a = new Cat();
a.sound(); // Meow (Cat's method)
}
}
Exception Rules
Cannot Throw New Checked Exceptions:
class Parent {
void method() { }
}
class Child extends Parent {
@Override
void method() throws IOException { } // ✗ Error
}
Can Throw Subclass Exception:
class Parent {
void method() throws Exception { }
}
class Child extends Parent {
@Override
void method() throws IOException { } // ✓ OK (IOException is subclass)
}
Quick Reference
class Parent {
void method() {
System.out.println("Parent");
}
}
class Child extends Parent {
@Override // Recommended
void method() { // Same signature
super.method(); // Optional: call parent
System.out.println("Child");
}
}
// Usage
Child c = new Child();
c.method(); // Calls Child's version
Parent p = new Child();
p.method(); // Also calls Child's version (polymorphism)
Exam Tips
Remember:
- Same signature required
- Use @Override annotation
- Cannot reduce access level
- Can increase access level
- Covariant return types allowed
- Use super to call parent method
- static methods not overridden (hidden)
- final methods cannot be overridden
- private methods not inherited (cannot override)
- Enables runtime polymorphism
Common Questions:
- What is method overriding?
- Rules for overriding?
- Overriding vs overloading?
- Can static methods be overridden?
- What is @Override annotation?
- Access modifier rules?
- Return type rules?
- How to call parent method?