Inheritance is an OOP mechanism that defines a new class by inheriting the fields and methods of an existing class. Common operations determined by the parent (super) can be used as is in the child (sub) or only some of them can be redefined (@Override), reducing code duplication.
Learning Objectives
- Inherit the class as
extends - Call the parent constructor with
super(...) - Know the role of
@Overrideannotation - Know the meaning of
finalof-class/method - I know that
protectedhas limited access open only to children.
Key concepts
1) extends and parent-child relationship
class Animal {
String name;
Animal(String name) { this.name = name; }
void speak() { System.out.println(name + ": ..."); }
}
class Dog extends Animal {
Dog(String name) { super(name); }
@Override
void speak() { System.out.println(name + ": Woof woof!"); }
}
Java only allows single inheritance. A class can have at most one parent.
2) super keyword
- In the constructor,
super(...)calls the parent constructor (must be the first line!) - Within the method,
super.method()calls the overridden parent method.
3) @Override
This annotation informs the compiler that the method to be overridden actually exists in the parent and is verified. Always attaching is recommended.
4) final
final class: Can no longer be inheritedfinalmethod: Overriding is not possible in children.finalfield: cannot be changed once initialized
5) protected
protected members can be accessed from the same package + child classes. Wider than private and narrower than public.
See as example
Example 1 — Animal.java + Dog.java: The most basic inheritance
Animal.java:
public class Animal {
protected String name;
public Animal(String name) { this.name = name; }
public void speak() {
System.out.println(name + ": (default cry)");
}
}
Dog.java:
public class Dog extends Animal {
public Dog(String name) { super(name); }
@Override
public void speak() {
System.out.println(name + ": Woof woof!");
}
public static void main(String[] args) {
Animal a = new Animal("animal");
Dog d = new Dog("Baduki");
a.speak();
d.speak();
}
}
Execution result
Animal: (default cry)
Baduki: Woof!
Note: Dog uses the name field of Animal (accessible as protected).
Example 2 — SuperKeyword.java : Utilizing super
class Base {
String tag() { return "[BASE]"; }
}
public class SuperKeyword extends Base {
@Override
String tag() {
return super.tag() + " + " + "[SUB]";
}
public static void main(String[] args) {
System.out.println(new SuperKeyword().tag());
}
}
Execution result
[BASE] + [SUB]
Note: super.method() is useful when you want a child to extend a parent method.
Example 3 — FinalDemo.java: Inheritance/redefinition blocking
public class FinalDemo {
static final class Constants {
static final double PI = 3.141592;
}
static class Base {
final void fixed() { System.out.println("No override"); }
void open() { System.out.println("Base.open"); }
}
static class Sub extends Base {
@Override
void open() { System.out.println("Sub.open"); }
//void fixed() { ... } // Compilation error: final method overriding prohibited
}
public static void main(String[] args) {
Sub s = new Sub();
s.fixed();
s.open();
System.out.println("PI=" + Constants.PI);
}
}
Execution result
No override
Sub.open
PI=3.141592
Note: final is used when you want to intentionally break inheritance.
Example 4 — MethodOverride.java: Various children
class Shape {
double area() { return 0.0; }
}
class Square extends Shape {
double side;
Square(double s) { this.side = s; }
@Override double area() { return side * side; }
}
class Circle extends Shape {
double radius;
Circle(double r) { this.radius = r; }
@Override double area() { return Math.PI * radius * radius; }
}
public class MethodOverride {
public static void main(String[] args) {
Shape[] shapes = { new Square(3), new Circle(2) };
for (Shape s : shapes) {
System.out.printf("area=%.3f%n", s.area());
}
}
}
Execution result
area=9.000
area=12.566
Note: If you call the same method with child objects in an array of parent types, the results will be different for each — just a taste of polymorphism (next section).
Common Mistakes
- Violating the rule that the parent constructor call must be the first line of the constructor.
@Overridewas omitted and the signature was slightly different, resulting in overloading (quiet bug)- Misunderstanding that you are overriding the
privatemethod (actually it is a new method) - Unreasonable inheritance (
extendseven though it is not an is-a relationship) - Deep inheritance hierarchy → reduced readability; Usually within 2~3 steps is recommended
Cleanup
- Inheritance is the basis for code reuse + polymorphism
- It is safe to attach
@Overrideunconditionally. - Intentional blocking possible with
final - composition is often a more flexible alternative to inheritance
Try it yourself
cd 02_object-oriented/08_inheritance/src
javac Animal.java Dog.java
java Dog