Java Method Overriding
In this page:
What is Method Overriding?
Method overriding lets a subclass supply its own implementation of a method the parent class already defines, which is the mechanism underneath runtime polymorphism — code calling the method through a parent-typed reference still gets the subclass's specific behavior.
Example: What is Method Overriding?
class Animal {
void sound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
@Override
void sound() { System.out.println("Bark"); }
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
a.sound(); // Bark, decided by actual object type
}
}
Login to try C/C++/Java/PHP code in the editor
Overriding Rules
For an override to be valid, the subclass method must match the parent's method exactly in name and parameter list, and its return type must be the same or a covariant (more specific) subtype — mismatching any of these creates a new overloaded method instead of an actual override.
Example: Overriding Rules
class Animal {
void sound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
@Override
void sound() { // same name, same parameters, same return type
System.out.println("Bark");
}
}
public class Main {
public static void main(String[] args) {
new Dog().sound();
}
}
Login to try C/C++/Java/PHP code in the editor
The @Override Annotation
The @Override annotation isn't strictly required, but it tells the compiler you intend to override a parent method, so if you accidentally mistype the signature, the compiler flags it as an error instead of silently letting you create an unrelated new method.
Example: The @Override Annotation
class Animal {
void sound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
@Override // compiler verifies this actually overrides a parent method
void sound() { System.out.println("Bark"); }
}
public class Main {
public static void main(String[] args) {
new Dog().sound();
}
}
Login to try C/C++/Java/PHP code in the editor
Dynamic Method Dispatch
Dynamic method dispatch is what decides, at runtime, which version of an overridden method actually executes — the JVM looks at the object's real, concrete type, not the type of the variable it's referenced through, which is why polymorphism works correctly through parent-typed references.
Example: Dynamic Method Dispatch
class Animal {
void sound() { System.out.println("Some sound"); }
}
class Dog extends Animal {
@Override
void sound() { System.out.println("Bark"); }
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
a.sound(); // JVM picks Dog's version at runtime, not Animal's
}
}
Login to try C/C++/Java/PHP code in the editor
Preventing Overriding with final
Marking a parent method final blocks any subclass from overriding it at all, which is the right tool when a method's behavior must be guaranteed identical everywhere it's inherited, such as core validation logic you never want a subclass to bypass.
Example: Preventing Overriding with final
class Animal {
final void identify() {
System.out.println("I am an animal");
}
}
class Dog extends Animal {
// void identify() {} // would not compile: identify() is final
}
public class Main {
public static void main(String[] args) {
new Dog().identify();
}
}
Login to try C/C++/Java/PHP code in the editor
Chapter Quiz — Complete all 7 topics to unlock
0/7 topics done
Complete these topics first: