Day 7: Inheritance and Polymorphism
What You'll Learn Today
- Inheritance (
extends) - Method overriding
- Abstract classes
- Interfaces
- Polymorphism
- Sealed classes (Java 17+)
Inheritance
Inheritance lets you create a new class by extending an existing one.
// Parent class (superclass)
public class Animal {
protected String name;
Animal(String name) {
this.name = name;
}
void speak() {
System.out.println(name + ": ...");
}
}
// Child class (subclass)
public class Dog extends Animal {
private String breed;
Dog(String name, String breed) {
super(name); // call the parent constructor
this.breed = breed;
}
@Override
void speak() {
System.out.println(name + ": Woof!");
}
void fetch() {
System.out.println(name + " fetched the ball!");
}
}
flowchart TB
Animal["Animal<br>name, speak()"]
Dog["Dog<br>breed, fetch()"]
Cat["Cat<br>indoor"]
Animal --> Dog
Animal --> Cat
style Animal fill:#3b82f6,color:#fff
style Dog fill:#22c55e,color:#fff
style Cat fill:#22c55e,color:#fff
| Term | Description |
|---|---|
extends |
Inherit from a class |
super |
Reference to the parent class |
@Override |
Override a method |
protected |
Accessible from subclasses |
Constraint: Java supports single inheritance only. A class can
extendsjust one other class.
Method Overriding
public class Cat extends Animal {
Cat(String name) {
super(name);
}
@Override
void speak() {
System.out.println(name + ": Meow!");
}
}
// Usage
Animal dog = new Dog("Buddy", "Shiba");
Animal cat = new Cat("Whiskers");
dog.speak(); // Buddy: Woof!
cat.speak(); // Whiskers: Meow!
Rules for Overriding
| Rule | Requirement |
|---|---|
| Method name | Must be the same |
| Parameters | Must be the same |
| Return type | Same or a subtype |
| Access modifier | Same or broader |
@Override |
Recommended |
Abstract Classes
An abstract class cannot be instantiated directly. It forces subclasses to provide specific implementations.
abstract class Shape {
String color;
Shape(String color) {
this.color = color;
}
// Abstract methods (no implementation)
abstract double area();
abstract double perimeter();
// Concrete method (has implementation)
void display() {
System.out.printf("%s: area=%.2f, perimeter=%.2f%n",
color, area(), perimeter());
}
}
class Circle extends Shape {
double radius;
Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
double area() {
return Math.PI * radius * radius;
}
@Override
double perimeter() {
return 2 * Math.PI * radius;
}
}
class Rectangle extends Shape {
double width, height;
Rectangle(String color, double width, double height) {
super(color);
this.width = width;
this.height = height;
}
@Override
double area() {
return width * height;
}
@Override
double perimeter() {
return 2 * (width + height);
}
}
When to use: Abstract classes are ideal when subclasses share common state (fields).
Interfaces
An interface defines a contract that classes must fulfill.
interface Printable {
void print(); // abstract method
}
interface Savable {
void save(String filename);
// Default method (Java 8+)
default void autoSave() {
save("auto_save.dat");
}
}
// Implementing multiple interfaces
class Document implements Printable, Savable {
private String content;
Document(String content) {
this.content = content;
}
@Override
public void print() {
System.out.println("Printing: " + content);
}
@Override
public void save(String filename) {
System.out.println("Saving to " + filename + ": " + content);
}
}
flowchart TB
Printable["<<interface>><br>Printable<br>print()"]
Savable["<<interface>><br>Savable<br>save(), autoSave()"]
Document["Document<br>content"]
Printable --> Document
Savable --> Document
style Printable fill:#8b5cf6,color:#fff
style Savable fill:#8b5cf6,color:#fff
style Document fill:#22c55e,color:#fff
Abstract Class vs Interface
| Feature | Abstract Class | Interface |
|---|---|---|
| Inheritance | Single only | Multiple allowed |
| Fields | Yes | Constants only |
| Constructors | Yes | No |
| Default methods | Yes | Yes (Java 8+) |
| Use case | Shared state and behavior | Defining contracts |
Polymorphism
Polymorphism allows different implementations to be called through the same type.
Shape[] shapes = {
new Circle("Red", 5),
new Rectangle("Blue", 4, 6),
new Circle("Green", 3)
};
for (Shape shape : shapes) {
shape.display(); // calls the appropriate subclass method
}
instanceof and Pattern Matching (Java 16+)
// Traditional approach
if (shape instanceof Circle) {
Circle c = (Circle) shape;
System.out.println("Radius: " + c.radius);
}
// Pattern matching (Java 16+)
if (shape instanceof Circle c) {
System.out.println("Radius: " + c.radius);
}
// Pattern matching in switch expressions (Java 21+)
String info = switch (shape) {
case Circle c -> "Circle (radius: " + c.radius + ")";
case Rectangle r -> "Rectangle (" + r.width + " x " + r.height + ")";
default -> "Unknown shape";
};
Sealed Classes (Java 17+)
Sealed classes restrict which classes can extend them.
sealed abstract class Payment permits CreditCard, BankTransfer, Cash {
abstract double amount();
}
final class CreditCard extends Payment {
private double amount;
private String cardNumber;
CreditCard(double amount, String cardNumber) {
this.amount = amount;
this.cardNumber = cardNumber;
}
@Override
double amount() { return amount; }
}
final class BankTransfer extends Payment {
private double amount;
BankTransfer(double amount) {
this.amount = amount;
}
@Override
double amount() { return amount; }
}
final class Cash extends Payment {
private double amount;
Cash(double amount) {
this.amount = amount;
}
@Override
double amount() { return amount; }
}
| Modifier | Description |
|---|---|
sealed |
Only permitted subclasses can inherit |
permits |
Lists the allowed subclasses |
final |
No further inheritance allowed |
non-sealed |
Removes the restriction |
Hands-On: Zoo Simulation
interface Feedable {
String favoriteFood();
}
abstract class Animal {
protected String name;
protected int age;
Animal(String name, int age) {
this.name = name;
this.age = age;
}
abstract String speak();
@Override
public String toString() {
return String.format("%s (%d years old)", name, age);
}
}
class Dog extends Animal implements Feedable {
Dog(String name, int age) { super(name, age); }
@Override
String speak() { return "Woof!"; }
@Override
public String favoriteFood() { return "Bones"; }
}
class Cat extends Animal implements Feedable {
Cat(String name, int age) { super(name, age); }
@Override
String speak() { return "Meow!"; }
@Override
public String favoriteFood() { return "Fish"; }
}
class Parrot extends Animal implements Feedable {
private String phrase;
Parrot(String name, int age, String phrase) {
super(name, age);
this.phrase = phrase;
}
@Override
String speak() { return phrase; }
@Override
public String favoriteFood() { return "Seeds"; }
}
public class Zoo {
public static void main(String[] args) {
Animal[] animals = {
new Dog("Buddy", 3),
new Cat("Whiskers", 5),
new Parrot("Polly", 2, "Hello there!")
};
System.out.println("=== Zoo ===");
for (Animal animal : animals) {
System.out.printf("%s -> %s", animal, animal.speak());
if (animal instanceof Feedable f) {
System.out.printf(" [Favorite food: %s]", f.favoriteFood());
}
System.out.println();
}
}
}
Summary
| Concept | Description |
|---|---|
| Inheritance | Extend an existing class with extends |
super |
Call parent class constructors and methods |
@Override |
Override a method from the parent |
| Abstract class | Cannot be instantiated; forces subclass implementation |
| Interface | A contract that supports multiple implementation |
| Polymorphism | Same type, different behavior |
sealed |
Restricts inheritance (Java 17+) |
| Pattern matching | Concise instanceof checks (Java 16+) |
Key Takeaways
- Java supports single inheritance (
extendsonly one class) - Interfaces allow multiple implementation
- Polymorphism makes your code flexible and extensible
sealedclasses provide safe, controlled inheritance
Exercises
Exercise 1: Basic
Create a Vehicle superclass, then extend it with Car and Bicycle. Override toString() in each subclass.
Exercise 2: Applied
Create a Student class that implements the Comparable interface so that students can be sorted by their grades.
Challenge
Using sealed classes, implement an area calculator with pattern matching (switch expressions). Support Circle, Rectangle, and Triangle, and return the area for each.
References
Next up: In Day 8, you'll learn about Exception Handling and File I/O -- mastering how Java deals with errors and file operations.