JSTAcademy
0 XP
Dashboard
Crash Courses
Classes, Inheritance & Interfaces
18 min
Masters+175 XP
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

ScenarioUse
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 behaviorInterface 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;
    }
}
0%