Crash Courses · Masters
Classes, Inheritance & Interfaces
Extend classes with inheritance, use abstract classes and polymorphism, and define behavior contracts with interfaces.
18 min read+175 XP on completionCert: Java / Kotlin Crash Course
Tap any word in the text below to start reading from there.
Classes, Inheritance & Interfaces
Inheritance with extends
// Superclass (parent)
public class Animal {
protected String name; // protected: accessible in subclasses
protected int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public String speak() {
return name + " makes a sound";
}
@Override
public String toString() {
return getClass().getSimpleName() + "[" + name + ", age=" + age + "]";
}
}
// Subclass inherits everything from Animal
public class Dog extends Animal {
private String breed;
public Dog(String name, int age, String breed) {
super(name, age); // MUST call parent constructor first
this.breed = breed;
}
@Override // replaces Animal.speak() for Dog instances
public String speak() {
return name + " barks: Woof!";
}
public String getBreed() { return breed; }
}
public class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);
}
@Override
public String speak() {
return name + " meows: Purrrr";
}
}Polymorphism in action:
Animal[] animals = {
new Dog("Rex", 3, "German Shepherd"),
new Cat("Whiskers", 5),
new Dog("Buddy", 2, "Labrador"),
};
for (Animal a : animals) {
System.out.println(a.speak()); // calls correct subclass speak() at runtime
}
// Rex barks: Woof!
// Whiskers meows: Purrrr
// Buddy barks: Woof!
// instanceof + pattern matching (Java 16+)
for (Animal a : animals) {
if (a instanceof Dog d) {
System.out.println(d.getBreed());
}
}---
Abstract Classes
Use abstract when the concept is too generic to instantiate directly but shares state:
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// abstract method: no body, subclasses MUST implement it
public abstract double area();
public abstract double perimeter();
// concrete method: shared by all shapes
public void describe() {
System.out.printf("%s %s: area=%.2f, perimeter=%.2f%n",
color, getClass().getSimpleName(), area(), perimeter());
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override public double area() { return Math.PI * radius * radius; }
@Override public double perimeter() { return 2 * Math.PI * radius; }
}
public class Square extends Shape {
private double side;
public Square(String color, double side) {
super(color);
this.side = side;
}
@Override public double area() { return side * side; }
@Override public double perimeter() { return 4 * side; }
}---
Interfaces
Interfaces define what a class can do without specifying how. A class can implement multiple interfaces:
public interface Printable {
void print(); // public abstract by default
}
public interface Saveable {
boolean save(String filepath);
// Default method: provides a default implementation
default String getSaveFormat() {
return "json";
}
}
public class Report implements Printable, Saveable {
private String title;
private String content;
public Report(String title, String content) {
this.title = title;
this.content = content;
}
@Override
public void print() {
System.out.println("=== " + title + " ===");
System.out.println(content);
}
@Override
public boolean save(String filepath) {
System.out.println("Saving to: " + filepath + "." + getSaveFormat());
return true;
}
}
// Use the interface type for polymorphism:
Printable p = new Report("Q4 Results", "Revenue: $1.2M");
p.print();---
Abstract Class vs. Interface: The Decision Rule
| Scenario | Use |
|---|---|
| Subclasses share **fields and state** | Abstract class |
| Subclasses share **behavior** (methods) | Abstract class |
| Defining a **capability** (can print, can save) | Interface |
| A class needs **multiple contracts** | Interfaces (since Java has single inheritance) |
| Retrofitting existing classes with new behavior | Interface default methods |
---
The super Keyword
public class LuxuryAccount extends BankAccount {
private double creditLimit;
public LuxuryAccount(String owner, double balance, double creditLimit) {
super(owner, balance); // call BankAccount constructor
this.creditLimit = creditLimit;
}
@Override
public boolean withdraw(double amount) {
// Can overdraft up to creditLimit
if (amount > getBalance() + creditLimit) return false;
// Call parent implementation, then adjust if needed
return super.withdraw(Math.min(amount, getBalance()))
|| adjustCredit(amount - getBalance());
}
private boolean adjustCredit(double amount) {
creditLimit -= amount;
return true;
}
}Reading progress
0% read
In this module
Inheritance
Polymorphism
Abstract Class
Interface
0%