Classes, Objects & Inheritance

Classes, constructors, encapsulation, inheritance, interfaces and polymorphism in Java.

Classes and objects

A class is a blueprint; an object is an instance of that blueprint created with new.

Java
public class Car {
    // fields (state)
    private String model;
    private int speed;

    // constructor
    public Car(String model) {
        this.model = model;
        this.speed = 0;
    }

    // methods (behaviour)
    public void accelerate(int amount) {
        this.speed += amount;
    }

    public String describe() {
        return model + " is going " + speed + " km/h";
    }
}
Java
Car car = new Car("Civic");
car.accelerate(40);
System.out.println(car.describe()); // Civic is going 40 km/h

Encapsulation

Fields are usually private, exposed only through public methods (getters/setters). This protects invariants — the class controls exactly how its state can change.

Java
public class BankAccount {
    private double balance;

    public void deposit(double amount) {
        if (amount <= 0) throw new IllegalArgumentException("Amount must be positive");
        balance += amount;
    }

    public double getBalance() {
        return balance;
    }
}

Inheritance

A subclass reuses and extends a parent class with extends:

Java
public class Vehicle {
    protected int speed = 0;

    public void accelerate() {
        speed += 10;
    }
}

public class SportsCar extends Vehicle {
    @Override
    public void accelerate() {
        speed += 30; // sports cars accelerate faster
    }
}
Java
Vehicle v = new SportsCar();
v.accelerate();
System.out.println(v.speed); // 30 — the overridden method ran

Every class in Java implicitly extends Object, which is why every object has .toString(), .equals() and .hashCode() by default.

Interfaces

An interface defines a contract — what a class must do, not how. A class can implement multiple interfaces (Java only allows single class inheritance, but unlimited interface implementation):

Java
public interface Payable {
    double calculatePay();
}

public class Employee implements Payable {
    private double hoursWorked;
    private double hourlyRate;

    public Employee(double hoursWorked, double hourlyRate) {
        this.hoursWorked = hoursWorked;
        this.hourlyRate = hourlyRate;
    }

    @Override
    public double calculatePay() {
        return hoursWorked * hourlyRate;
    }
}

Polymorphism

Different classes implementing the same interface (or extending the same parent) can be treated uniformly:

Java
List<Payable> payables = List.of(
    new Employee(40, 25.0),
    new Employee(20, 30.0)
);

double total = 0;
for (Payable p : payables) {
    total += p.calculatePay(); // each object runs its own implementation
}

Abstract classes

Use an abstract class when subclasses should share some real implementation and be forced to implement other parts themselves:

Java
public abstract class Shape {
    public abstract double area();       // must be implemented by subclasses

    public void printArea() {            // shared, concrete implementation
        System.out.println("Area: " + area());
    }
}

public class Circle extends Shape {
    private double radius;
    public Circle(double radius) { this.radius = radius; }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

Best practices

  • Favor composition over inheritance where possible — deep inheritance hierarchies become fragile to change.
  • Keep fields private and expose behaviour through methods, not raw setters for everything.
  • Program to an interface, not a concrete class (Payable p = new Employee(...), not Employee e = ...), so implementations can be swapped freely.

Common mistakes

  • Forgetting @Override — it's optional but catches typos in method signatures at compile time.
  • Confusing an abstract class (can have state + concrete methods) with an interface (traditionally contract-only, though modern Java interfaces can have default methods too).
  • Overusing inheritance for code reuse when composition would be simpler and more flexible.

Interview questions

Q: When would you use an abstract class instead of an interface? When subclasses need to share actual field state and some concrete method implementations, not just a method contract. A class can only extend one abstract class but can implement many interfaces.

Q: What is polymorphism, concretely? The ability to call the same method name on different object types and have each execute its own behaviour — enabled by inheritance/interfaces plus method overriding, resolved at runtime ("dynamic dispatch").