7.1 OOP II — Inheritance & Polymorphism Overview
Note: This guide is based on Java 21.
So far you have learned the basics of Java OOP — classes, objects, methods, constructors, and overloading. This chapter dives deep into the crown jewels of object-oriented programming: Inheritance, Polymorphism, Abstraction, and Encapsulation.
1. OOP II Topics Overview
| Topic | Keyword | Core Concept |
|---|---|---|
| Inheritance | extends | Reuse a parent class's fields and methods in a child class |
| Polymorphism | @Override, up/downcasting | Handle many types with a single piece of code |
| Abstraction | abstract, interface | Define common behavior and delegate implementation to subclasses |
| Encapsulation | private, getter/setter | Hide data and provide safe access paths |
2. Introduction to Inheritance
Inheritance is the mechanism by which a new class (child/subclass) acquires the fields and methods of an existing class (parent/superclass).
The extends Keyword
// Parent class
public class Animal {
String name;
int age;
void eat() {
System.out.println(name + " is eating.");
}
void sleep() {
System.out.println(name + " is sleeping.");
}
}
// Child class: inherits from Animal
public class Dog extends Animal {
String breed; // field unique to child
void bark() { // method unique to child
System.out.println(name + " barks: Woof!");
}
}
Benefits of Inheritance
- Code Reuse: No need to duplicate code that already exists in the parent class
- IS-A Relationship: "A dog IS an animal" — logically sound
- Maintainability: Changes to the parent class automatically propagate to all children
- Extensibility: New functionality can be added without modifying existing code
public class InheritanceTest {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "Buddy"; // field inherited from parent
dog.age = 3; // field inherited from parent
dog.breed = "Jindo"; // field unique to child
dog.eat(); // inherited method: Buddy is eating.
dog.sleep(); // inherited method: Buddy is sleeping.
dog.bark(); // child method: Buddy barks: Woof!
}
}
3. Inheritance Hierarchy and the Object Class
Every class in Java implicitly has java.lang.Object as its ultimate ancestor.
Object
└── Animal
├── Dog
│ ├── Poodle
│ └── Husky
├── Cat
└── Bird
├── Parrot
└── Eagle
// Even without writing it, Animal implicitly extends Object
class Animal extends Object { ... } // this is what it actually means
// Key Object methods — inherited by every class
Object obj = new Dog();
obj.toString(); // string representation of the object
obj.equals(obj); // equality comparison
obj.hashCode(); // hash code
obj.getClass(); // runtime class info
4. Why Only Single Inheritance — The Diamond Problem
Java does not allow multiple class inheritance. A class can only extends one parent class.
// Not allowed! Java forbids multiple inheritance
// class SmartPhone extends Phone, Camera { } // compile error
// OK: single inheritance
class SmartPhone extends Phone { ... }
The Diamond Problem
Animal
/ \
Dog Cat
\ /
DogCat? ← Diamond Problem!
If both Dog and Cat override Animal's sound() method differently, it would be ambiguous which version DogCat should invoke. Java prevents this by banning multiple class inheritance.
5. Multiple Implementation via Interfaces
As an alternative, Java allows multiple interface implementations.
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
interface Runnable {
void run();
}
// A class can implement multiple interfaces
class Duck extends Animal implements Flyable, Swimmable, Runnable {
@Override
public void fly() { System.out.println("Duck flies!"); }
@Override
public void swim() { System.out.println("Duck swims!"); }
@Override
public void run() { System.out.println("Duck runs!"); }
}
6. Practical Example: Animal Hierarchy
// Top-level parent: common attributes and behaviors for all animals
public class Animal {
protected String name;
protected String sound;
protected int legs;
public Animal(String name, String sound, int legs) {
this.name = name;
this.sound = sound;
this.legs = legs;
}
public void makeSound() {
System.out.println(name + ": " + sound);
}
public void move() {
System.out.println(name + " moves on " + legs + " legs.");
}
public void introduce() {
System.out.printf("I am %s. I have %d legs and say '%s'.%n",
name, legs, sound);
}
}
// Child 1: Dog
public class Dog extends Animal {
private String breed;
public Dog(String name, String breed) {
super(name, "Woof", 4); // call parent constructor
this.breed = breed;
}
public void fetch() {
System.out.println(name + " fetches the ball!");
}
@Override
public void introduce() {
super.introduce();
System.out.println("Breed: " + breed);
}
}
// Child 2: Cat
public class Cat extends Animal {
private boolean isIndoor;
public Cat(String name, boolean isIndoor) {
super(name, "Meow", 4);
this.isIndoor = isIndoor;
}
public void purr() {
System.out.println(name + " purrs~");
}
@Override
public void introduce() {
super.introduce();
System.out.println("Indoor cat: " + (isIndoor ? "Yes" : "No"));
}
}
// Child 3: Bird
public class Bird extends Animal {
private double wingspan;
public Bird(String name, double wingspan) {
super(name, "Tweet", 2);
this.wingspan = wingspan;
}
public void fly() {
System.out.printf("%s flies with a %.1f cm wingspan!%n", name, wingspan);
}
}
// Test
public class AnimalTest {
public static void main(String[] args) {
Animal[] animals = {
new Dog("Buddy", "Jindo"),
new Cat("Luna", true),
new Bird("Sparrow", 20.5)
};
System.out.println("=== Animal Introduction ===");
for (Animal a : animals) {
a.introduce(); // polymorphism: each type's introduce()
a.makeSound(); // polymorphism: each type's sound
System.out.println("---");
}
// Child-specific methods require downcasting
Dog dog = (Dog) animals[0];
dog.fetch();
Cat cat = (Cat) animals[1];
cat.purr();
Bird bird = (Bird) animals[2];
bird.fly();
}
}
Output:
=== Animal Introduction ===
I am Buddy. I have 4 legs and say 'Woof'.
Breed: Jindo
Buddy: Woof
---
I am Luna. I have 4 legs and say 'Meow'.
Indoor cat: Yes
Luna: Meow
---
I am Sparrow. I have 2 legs and say 'Tweet'.
Sparrow: Tweet
---
Buddy fetches the ball!
Luna purrs~
Sparrow flies with a 20.5 cm wingspan!
7. Preview of Chapter 7 Topics
| Section | Topic | Key Content |
|---|---|---|
| 7.2 Inheritance | extends, super(), method overriding | Parent-child relationship, constructor chaining |
| 7.3 Polymorphism | Upcasting, downcasting, instanceof | Flexible code, dynamic binding |
| 7.4 Abstraction | abstract, interface | Design tools, contract-based programming |
| 7.5 Encapsulation | private, getter/setter, Record | Data protection, immutable classes |
| 7.6 super | super.field, super.method(), super() | Accessing parent members, constructor chaining |
Inheritance, polymorphism, abstraction, and encapsulation are not just syntax. They are the foundation of every advanced technique used in industry: design patterns, SOLID principles, and the Spring Boot framework. Mastering this chapter is your launchpad to becoming a professional Java developer.
Summary
| Concept | Core Idea |
|---|---|
| Inheritance | Reuse parent fields and methods via extends |
| Object class | The ultimate ancestor of every class |
| Single inheritance | Prevents the diamond problem; a class may extend only one class |
| Multiple implementation | Multiple interfaces can be implemented via implements |
| IS-A relationship | Inheritance should reflect a logical hierarchy |