🌱BeginnerObject-Oriented Programming

Interfaces

Define contracts that classes must fulfill using interfaces - Java's way of achieving multiple inheritance and loose coupling.

Overview

An interface is a pure contract - it declares what methods a class must have, without providing any implementation (except optional default methods added in Java 8+). A class implements an interface by providing a body for each declared method. Interfaces solve two problems: (1) Java has single inheritance for classes, but a class can implement any number of interfaces. (2) Interfaces decouple code - you depend on the contract (interface) rather than a specific implementation, making code more flexible. Common examples from the Java standard library: Comparable (compareTo), Iterable (iterator()), Runnable (run()), Serializable.

Key Points

  • •interface keyword: `interface Drawable { void draw(); }`
  • •implements keyword: `class Circle implements Drawable { ... }`
  • •All interface methods are implicitly public abstract (before Java 8)
  • •A class can implement multiple interfaces: `class A implements B, C, D`
  • •Interface fields are implicitly public static final (constants)
  • •Java 8+ allows default methods (with a body) and static methods in interfaces
  • •Interfaces support polymorphism: a variable of interface type can hold any implementing class
  • •Unlike abstract classes, interfaces cannot have instance fields (only constants)

Examples

Defining and implementing an interface

interface Drawable {
    void draw();         // abstract
    void resize(int factor);
}

interface Colourable {
    void setColour(String colour);
    String getColour();
}

// A class can implement multiple interfaces
class Square implements Drawable, Colourable {
    int side;
    private String colour = "black";

    Square(int side) { this.side = side; }

    @Override
    public void draw() {
        System.out.println("Drawing a " + colour + " square of side " + side);
    }

    @Override
    public void resize(int factor) {
        side *= factor;
        System.out.println("Resized to " + side);
    }

    @Override
    public void setColour(String colour) { this.colour = colour; }

    @Override
    public String getColour() { return colour; }
}

public class Main {
    public static void main(String[] args) {
        Square sq = new Square(5);
        sq.setColour("red");
        sq.draw();
        sq.resize(2);
        sq.draw();
    }
}

Square must implement draw(), resize(), setColour(), and getColour() - the compiler enforces this.

Interface as a type (polymorphism)

interface Printable {
    void print();
}

class Invoice implements Printable {
    int id;
    Invoice(int id) { this.id = id; }
    @Override public void print() { System.out.println("Invoice #" + id); }
}

class Report implements Printable {
    String title;
    Report(String title) { this.title = title; }
    @Override public void print() { System.out.println("Report: " + title); }
}

public class Main {
    // Method accepts any Printable - doesn't care which class
    static void printAll(Printable[] items) {
        for (Printable p : items) p.print();
    }

    public static void main(String[] args) {
        Printable[] docs = {
            new Invoice(101),
            new Report("Annual Summary"),
            new Invoice(202)
        };
        printAll(docs);
    }
}

printAll() only knows about Printable - it works with any class that implements it, even ones written after printAll() was created.

Default methods (Java 8+)

interface Greeter {
    String getName();

    // Default method - provided by the interface
    default void greet() {
        System.out.println("Hello, " + getName() + "!");
    }

    default void farewell() {
        System.out.println("Goodbye, " + getName() + "!");
    }
}

class FormalGreeter implements Greeter {
    private String name;
    FormalGreeter(String name) { this.name = name; }

    @Override
    public String getName() { return name; }

    @Override // Override the default if needed
    public void greet() {
        System.out.println("Good day, " + name + ". How do you do?");
    }
}

public class Main {
    public static void main(String[] args) {
        FormalGreeter fg = new FormalGreeter("Sir Edmund");
        fg.greet();    // overridden version
        fg.farewell(); // default version from interface
    }
}

Default methods let you add new methods to an interface without breaking all existing implementations.

Common Mistakes

  • Using extends for interface implementation - use implements, not extends (unless one interface is extending another interface)
  • Forgetting to implement all interface methods - the class must be abstract if any are missing
  • Adding instance fields to an interface - interfaces only allow public static final constants, not mutable instance fields

Note

Prefer interfaces over abstract classes when you just need to define a contract. Interfaces allow multiple implementations and fit better with Java's single-inheritance rule. Use abstract classes when you also want to share fields or concrete method implementations.

Exercises

Write Java code and click Run to execute it instantly. When your output looks correct, mark as done.

Loading editor…

Completed: 0 / 4 exercises

Knowledge Check

Question 1 of 4

What keyword does a class use to fulfill an interface contract?