Java > Object-Oriented Programming (OOP) > Inheritance > Method Overriding
Method Overriding Example: Animal and Dog
This example demonstrates method overriding in Java using an Animal
class and its subclass, Dog
. The makeSound()
method is overridden in the Dog
class to provide a specific implementation for dogs. Method overriding is a key feature of OOP that allows subclasses to provide their own implementations of methods defined in their superclasses.
Code Snippet
The Animal
class defines a method makeSound()
that prints a generic animal sound. The Dog
class inherits from Animal
and overrides the makeSound()
method to print 'Woof!'. The @Override
annotation is optional but recommended as it helps the compiler catch errors if the method signature doesn't match the superclass method. The Main
class demonstrates how the overridden method is called based on the object type, not the reference type. Specifically, when animalDog.makeSound()
is called, the Dog
's makeSound()
method is executed due to dynamic method dispatch.
// Base class (Superclass)
class Animal {
public void makeSound() {
System.out.println("Generic animal sound");
}
}
// Subclass (Inherits from Animal)
class Dog extends Animal {
@Override // Optional annotation, but good practice
public void makeSound() {
System.out.println("Woof!");
}
public void fetch() {
System.out.println("Dog is fetching the ball.");
}
}
// Main class to test the code
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
animal.makeSound(); // Output: Generic animal sound
Dog dog = new Dog();
dog.makeSound(); // Output: Woof!
dog.fetch(); // Output: Dog is fetching the ball.
Animal animalDog = new Dog(); //Upcasting
animalDog.makeSound(); //Output: Woof! (Dynamic method dispatch)
}
}
Concepts Behind Method Overriding
Method overriding allows a subclass to provide a specific implementation for a method that is already defined in its superclass. This enables polymorphism, where objects of different classes can respond differently to the same method call. Key requirements for method overriding include: same method name, same parameter list (argument list), and compatible return type. The access modifier for the overriding method can be the same or more accessible than the overridden method (e.g., protected -> public is allowed, but public -> protected is not).
Real-Life Use Case
Consider a drawing application where you have a base class Shape
with a method draw()
. Different shapes like Circle
, Rectangle
, and Triangle
can inherit from Shape
and override the draw()
method to provide their specific drawing logic. This allows you to call draw()
on any Shape
object, and the correct drawing routine will be executed based on the actual type of the object.
Best Practices
@Override
annotation to ensure that you are correctly overriding a method. This helps prevent errors and improves code readability.
Interview Tip
Be prepared to explain the difference between method overriding and method overloading. Method overriding occurs when a subclass provides a specific implementation for a method already defined in its superclass, while method overloading occurs when a class has multiple methods with the same name but different parameter lists. Emphasize the role of inheritance in method overriding.
When to Use Method Overriding
Use method overriding when you want a subclass to provide a specialized implementation of a method that is already defined in its superclass. This is useful when the default behavior of the superclass method is not appropriate for the subclass, or when you want to add or modify the behavior of the method in the subclass.
Alternatives
An alternative to method overriding, especially when the behavior varies greatly and isn't predictable, is using composition and interfaces. You could inject different strategy objects (implementing a common interface) to provide the required functionality instead of relying on inheritance and overriding.
Pros
Cons
FAQ
-
What happens if I don't use the @Override annotation?
The code will still compile and run correctly if you don't use the@Override
annotation, as long as the method signature matches the superclass method. However, using the annotation is highly recommended because it allows the compiler to catch errors if you accidentally misspell the method name or use the wrong parameter list. It also improves code readability by making it clear that the method is intended to override a superclass method. -
Can I override a method to throw a broader exception than the superclass method?
No, you cannot override a method to throw a broader checked exception than the superclass method. However, you can throw a narrower checked exception or any unchecked exception. If the superclass method doesn't throw any exception, you can only throw unchecked exceptions in the overriding method. This is due to the Liskov Substitution Principle. -
Can I override a private method?
No, you cannot override a private method. Private methods are not inherited by subclasses. If you define a method with the same name and signature in a subclass, it's considered a new method, not an override. -
What is dynamic method dispatch?
Dynamic method dispatch (also known as runtime polymorphism) is the mechanism by which the correct version of an overridden method is called at runtime based on the actual type of the object. When you call a method on an object, the Java Virtual Machine (JVM) determines the appropriate method to execute based on the object's actual class, not the reference type. This is what enables polymorphism and allows you to treat objects of different classes as objects of a common type.