Interfaces

Lesson 0011 — 40 min read

An interface defines a contract — a set of method signatures that implementing classes must fulfill. Focus on what, not how.

Basic Interface

interface Animal {
    void eat();
    void sleep();
}

class Dog implements Animal {
    @Override
    public void eat() { System.out.println("Dog eats bones."); }

    @Override
    public void sleep() { System.out.println("Dog sleeps in a kennel."); }
}
class Animal {
public:
    virtual void eat() = 0;
    virtual void sleep() = 0;
    virtual ~Animal() = default;
};

class Dog : public Animal {
public:
    void eat() override { cout << "Dog eats bones." << endl; }
    void sleep() override { cout << "Dog sleeps in a kennel." << endl; }
};
from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def eat(self): pass

    @abstractmethod
    def sleep(self): pass

class Dog(Animal):
    def eat(self): print("Dog eats bones.")
    def sleep(self): print("Dog sleeps in a kennel.")

Can Interfaces Have Instance Variables?

No. All fields in an interface are implicitly public static final (constants). Since interfaces can't have state, there's nothing to initialize.

Can Interfaces Have Constructors?

No. Constructors initialize object state; interfaces have no state. Implementing classes provide their own constructors.

interface Vehicle { void start(); }

class Car implements Vehicle {
    private String brand;
    Car(String brand) { this.brand = brand; }

    @Override
    public void start() {
        System.out.println(brand + " car is starting.");
    }
}
class Vehicle {
public:
    virtual void start() = 0;
    virtual ~Vehicle() = default;
};

class Car : public Vehicle {
    string brand;
public:
    Car(string b) : brand(b) {}
    void start() override {
        cout << brand << " car is starting." << endl;
    }
};
class Vehicle(ABC):
    @abstractmethod
    def start(self): pass

class Car(Vehicle):
    def __init__(self, brand):
        self.__brand = brand

    def start(self):
        print(f"{self.__brand} car is starting.")

Multiple Interfaces

A class can implement multiple interfaces. Java uses this instead of multiple class inheritance (avoiding the diamond problem).

interface Flyable  { void fly(); }
interface Swimmable { void swim(); }

class Duck implements Flyable, Swimmable {
    @Override
    public void fly() { System.out.println("Duck is flying."); }

    @Override
    public void swim() { System.out.println("Duck is swimming."); }
}
class Flyable {
public:
    virtual void fly() = 0;
    virtual ~Flyable() = default;
};

class Swimmable {
public:
    virtual void swim() = 0;
    virtual ~Swimmable() = default;
};

class Duck : public Flyable, public Swimmable {
public:
    void fly() override { cout << "Duck is flying." << endl; }
    void swim() override { cout << "Duck is swimming." << endl; }
};
class Flyable(ABC):
    @abstractmethod
    def fly(self): pass

class Swimmable(ABC):
    @abstractmethod
    def swim(self): pass

class Duck(Flyable, Swimmable):
    def fly(self): print("Duck is flying.")
    def swim(self): print("Duck is swimming.")

Key Features of Interfaces

PaymentGateway Example

Clients use PaymentGateway without knowing whether they're talking to PayPal or Stripe.

interface PaymentGateway {
    void processPayment(double amount);
}

class PayPal implements PaymentGateway {
    @Override
    public void processPayment(double amount) {
        System.out.println("PayPal: $" + amount);
    }
}

class Stripe implements PaymentGateway {
    @Override
    public void processPayment(double amount) {
        System.out.println("Stripe: $" + amount);
    }
}
class PaymentGateway {
public:
    virtual void processPayment(double amount) = 0;
    virtual ~PaymentGateway() = default;
};

class PayPal : public PaymentGateway {
public:
    void processPayment(double amount) override {
        cout << "PayPal: $" << amount << endl;
    }
};

class Stripe : public PaymentGateway {
public:
    void processPayment(double amount) override {
        cout << "Stripe: $" << amount << endl;
    }
};
class PaymentGateway(ABC):
    @abstractmethod
    def processPayment(self, amount): pass

class PayPal(PaymentGateway):
    def processPayment(self, amount):
        print(f"PayPal: ${amount}")

class Stripe(PaymentGateway):
    def processPayment(self, amount):
        print(f"Stripe: ${amount}")

Static Methods in Interfaces

Called on the interface/class itself, not on instances. Cannot access instance variables.

interface Example {
    static void staticMethod() {
        System.out.println("Static method in interface.");
    }
}

Example.staticMethod();  // Called on interface
class Example {
public:
    static void staticMethod() {
        cout << "Static method." << endl;
    }
};

Example::staticMethod();  // Called on class
class Example:
    @staticmethod
    def staticMethod():
        print("Static method.")

Example.staticMethod()  # Called on class

Default Methods (Java 8+)

Allow adding methods to interfaces without breaking existing implementations. Before Java 8, adding a method broke all classes that implemented it.

interface Example {
    default void defaultMethod() {
        System.out.println("Default implementation.");
    }
}

class Demo implements Example { }

Example obj = new Demo();
obj.defaultMethod();  // Inherits default
// C++ has no interface default methods.
// Achieve via base class with concrete method.
# Python has no interface default methods.
# Achieve via base class with concrete method.

Interface Inheritance

Interfaces can extend other interfaces, adding methods to the contract.

interface Animal { void eat(); }
interface Mammal extends Animal { void walk(); }

class Human implements Mammal {
    @Override
    public void eat() { System.out.println("Human eats food."); }

    @Override
    public void walk() { System.out.println("Human walks on two legs."); }
}
class Animal {
public:
    virtual void eat() = 0;
    virtual ~Animal() = default;
};

class Mammal : public Animal {
public:
    virtual void walk() = 0;
    virtual ~Mammal() = default;
};

class Human : public Mammal {
public:
    void eat() override { cout << "Human eats food." << endl; }
    void walk() override { cout << "Human walks on two legs." << endl; }
};
class Animal(ABC):
    @abstractmethod
    def eat(self): pass

class Mammal(Animal):
    @abstractmethod
    def walk(self): pass

class Human(Mammal):
    def eat(self): print("Human eats food.")
    def walk(self): print("Human walks on two legs.")

What happens if a class implements two interfaces with the same default method signature (Java)?

What fields can you declare in a Java interface?

Notes

Interfaces :-

Interface ⇒ contract ; specifies WHAT methods must exist, not HOW they are implemented

Methods ⇒ implicitly public abstract (pre-Java 8)

Fields ⇒ implicitly public static final (constants only)

Constructors ⇒ not allowed (interfaces hold no instance state)

Multiple Interfaces :-

Java ⇒ a class can implement multiple interfaces (avoiding class diamond problem)

C++ ⇒ multiple inheritance via abstract classes with pure virtual functions

Python ⇒ multiple inheritance using Abstract Base Classes (ABCs)

Default & Static Methods :-

Default methods ⇒ default keyword provides body in interface to evolve API without breaking callers

Conflict rule ⇒ if two interfaces provide same default signature, implementing class must override it

Interface vs Abstract Class :-

Abstract class ⇒ can have state, constructors, concrete + abstract methods ; single inheritance

Interface ⇒ no state, no constructors, contract focus ; multiple inheritance supported

Primary source: Oracle Java Tutorials — Interfaces. Ask me anything that's unclear.

← Prev: Abstraction Next: The static Keyword →

Questions? Ask your agent — you can follow up on any concept, quiz answer, or how this applies to a specific coding problem. Review the Java glossary or syntax quick reference for a compressed overview.