Skip to content

Java Interfaces

Updated 9 min read Aimerscrew

A Java interface describes what an object can do without saying how it does it. It's a list of method promises, a contract, that any class can sign up for, no matter which family the class belongs to. In this lesson, you'll learn how to write and implement interfaces, how one class can have several of them, what default and static methods are, and how to choose between an interface and an abstract class.

🌍 Real-life example

A USB-C port is an interface. Your phone, your laptop, an electric toothbrush and a pair of headphones are completely different products from different companies, but they all promise the same thing: "plug a USB-C cable in here and I'll charge". The charger doesn't care what the device is. It only cares that the device keeps that promise.

What is an interface in Java?

An interface is a reference type that lists method signatures a class must provide. Think of it as a capability: "can be charged", "can be printed", "can be shipped". You declare one with the interface keyword, and a class promises to fulfil it with the implements keyword:

public class ChargingStation {
    public static void main(String[] args) {
        Chargeable[] devices = { new Phone(), new ElectricCar(), new Laptop() };

        for (Chargeable d : devices) {
            d.charge(30);
        }
    }
}

interface Chargeable {
    void charge(int minutes);   // automatically public and abstract
}

class Phone implements Chargeable {
    private int battery = 20;

    @Override
    public void charge(int minutes) {
        battery = Math.min(100, battery + minutes * 2);
        System.out.println("Phone battery: " + battery + "%");
    }
}

class ElectricCar implements Chargeable {
    private int rangeKm = 50;

    @Override
    public void charge(int minutes) {
        rangeKm += minutes * 5;
        System.out.println("Car range: " + rangeKm + " km");
    }
}

class Laptop implements Chargeable {
    private int battery = 55;

    @Override
    public void charge(int minutes) {
        battery = Math.min(100, battery + minutes);
        System.out.println("Laptop battery: " + battery + "%");
    }
}
Phone battery: 80%
Car range: 200 km
Laptop battery: 85%

A phone, a car and a laptop have nothing else in common, so making them share a parent class would be strange. The interface lets them share just the one ability that matters here. The array type is the interface, and polymorphism runs each class's own charge().

Animated diagram: the Chargeable interface is a contract with one method, charge(int minutes). Three unrelated classes, Phone, ElectricCar and Laptop, each connect to it with a dashed implements arrow and get a check mark once they provide their own charge() method
Unrelated classes can sign the same contract. Dashed arrows mean "implements".

The rules of implementing an interface

  • Methods declared in an interface without a body are automatically public and abstract. You don't need to write either word.
  • The implementing class must provide every abstract method, or be declared abstract itself.
  • The implementing method must be public. Leaving out public gives the error attempting to assign weaker access privileges; was public.
  • Use @Override on implemented methods too, so the compiler checks the name and parameters.
  • You can't create an object of an interface with new Chargeable(), but you can use it as a variable, parameter or array type.

Can a class implement multiple interfaces?

Yes. A class can extend only one class, but it can implement as many interfaces as you like, separated by commas. This is how Java gives you the useful part of multiple inheritance without the confusion.

public class DroneFleet {
    public static void main(String[] args) {
        DeliveryDrone drone = new DeliveryDrone("DX-7");
        drone.charge(15);
        System.out.println(drone.location());

        Chargeable c = drone;   // the same object, seen as Chargeable
        Trackable t = drone;    // ...or as Trackable
        c.charge(5);
        System.out.println(t.location());
    }
}

interface Chargeable {
    void charge(int minutes);
}

interface Trackable {
    String location();
}

class DeliveryDrone implements Chargeable, Trackable {
    private String id;
    private int battery = 40;

    DeliveryDrone(String id) {
        this.id = id;
    }

    @Override
    public void charge(int minutes) {
        battery = Math.min(100, battery + minutes * 3);
        System.out.println(id + " battery: " + battery + "%");
    }

    @Override
    public String location() {
        return id + " is above Warehouse 3";
    }
}
DX-7 battery: 85%
DX-7 is above Warehouse 3
DX-7 battery: 100%
DX-7 is above Warehouse 3

A charging station only needs to see the drone as Chargeable; a map screen only needs it as Trackable. Each part of the program sees just the abilities it cares about. A class can also extend a class and implement interfaces: class DeliveryDrone extends Aircraft implements Chargeable, Trackable (the extends part comes first).

Default methods, static methods and constants

Since Java 8, an interface can contain more than abstract methods:

  • A default method has a body and the keyword default. Implementing classes get it for free and may override it.
  • A static method belongs to the interface itself. You call it as InterfaceName.method(); it isn't inherited by objects.
  • A field in an interface is automatically public static final, which makes it a constant.
public class ShippingDesk {
    public static void main(String[] args) {
        Shippable[] parcels = { new Book("Java for Beginners", 0.4), new Laptop(2.1) };

        for (Shippable p : parcels) {
            printLabel(p);
        }
        System.out.println("Flat fee: " + Shippable.format(Shippable.BASE_FEE));
    }

    // Works with ANY Shippable, now and in the future
    static void printLabel(Shippable item) {
        System.out.println(item.label() + " -> " + Shippable.format(item.shippingCost()));
    }
}

interface Shippable {
    double BASE_FEE = 4.99;               // a constant: public static final

    double weightKg();                    // abstract: each class must write it
    String label();

    default double shippingCost() {       // default: a ready-made body
        return BASE_FEE + weightKg() * 2.0;
    }

    static String format(double amount) { // static: belongs to the interface
        return String.format("$%.2f", amount);
    }
}

class Book implements Shippable {
    private String title;
    private double weight;

    Book(String title, double weight) {
        this.title = title;
        this.weight = weight;
    }

    @Override
    public double weightKg() {
        return weight;
    }

    @Override
    public String label() {
        return "Book: " + title;
    }
}

class Laptop implements Shippable {
    private double weight;

    Laptop(double weight) {
        this.weight = weight;
    }

    @Override
    public double weightKg() {
        return weight;
    }

    @Override
    public String label() {
        return "Laptop";
    }

    @Override
    public double shippingCost() {        // overriding a default method
        return Shippable.super.shippingCost() + 10.0;   // fragile item fee
    }
}
Book: Java for Beginners -> $5.79
Laptop -> $19.19
Flat fee: $4.99

Book uses the default shippingCost() as is. Laptop overrides it and calls the default version with the special syntax Shippable.super.shippingCost(), then adds a fragile-item fee. String.format() works like printf but returns the text instead of printing it.

📝 Note

Default methods were added so that Java could add new methods to old interfaces without breaking every class that already implemented them. Use them for sensible shared behavior, not as a way to stuff lots of code into an interface.

Programming to an interface

Look again at printLabel(Shippable item) above. Its parameter type is the interface, not Book or Laptop. That method will work with any class that implements Shippable, including classes nobody has written yet. This habit is called programming to an interface: declare variables and parameters using the most general type that has the methods you need.

You'll see this everywhere in real Java code. For example, programmers write List<String> names = new ArrayList<>(); rather than ArrayList<String> names, because List is an interface. You'll meet it in the Java Collections Framework.

💡 Tip

Name interfaces after an ability or a role. Adjectives ending in "-able" (Chargeable, Printable, Comparable) read nicely: "a Laptop is Shippable".

Interface vs abstract class: which should you use?

InterfaceAbstract class
Keywordinterface / implementsabstract class / extends
How many per class?ManyOnly one
Instance fields (state)No, only constantsYes
ConstructorsNoYes
Methods with a bodydefault and static methodsAny normal method
Method accessPublic by defaultAny modifier
Relationship"can do" (a capability)"is a" (a family)
Best forUnrelated classes sharing an abilityRelated classes sharing code and data

When in doubt, start with an interface. It keeps your classes free to extend something else later. You can also combine both: an abstract class that implements an interface and provides shared code for its subclasses.

Sealed interfaces (Java 17)

Normally, any class can implement an interface. Sometimes you want a closed list: "a parking lot vehicle is a Car or a Motorbike, nothing else". A sealed interface uses the sealed and permits keywords to name exactly which classes may implement it:

public class ParkingFees {
    public static void main(String[] args) {
        ParkedVehicle[] lot = { new Car(), new Motorbike(), new Car() };
        double total = 0;
        for (ParkedVehicle v : lot) {
            total += v.hourlyRate() * 3;
        }
        System.out.printf("3 hours for %d vehicles: $%.2f%n", lot.length, total);
    }
}

sealed interface ParkedVehicle permits Car, Motorbike {
    double hourlyRate();
}

final class Car implements ParkedVehicle {
    @Override
    public double hourlyRate() {
        return 2.50;
    }
}

final class Motorbike implements ParkedVehicle {
    @Override
    public double hourlyRate() {
        return 1.00;
    }
}
3 hours for 3 vehicles: $18.00

Each permitted class must say how the chain continues: final (no more subclasses), sealed (its own closed list) or non-sealed (open again). If a Truck tries to implement ParkedVehicle, the compiler refuses: class is not allowed to extend sealed class: ParkedVehicle. Classes can be sealed in the same way.

Common mistakes with interfaces

1. Forgetting public on the implementing method

Interface methods are public, so void charge(int m) { } in the class fails with attempting to assign weaker access privileges; was public. Write public void charge(int m).

2. Using extends instead of implements

A class implements an interface: class Phone implements Chargeable. (An interface can extend another interface, though: interface FastChargeable extends Chargeable.)

3. Trying to store state in an interface

A field like int battery = 50; inside an interface becomes a shared public static final constant, not a per-object field. You can't change it. Keep object data in the classes.

4. Calling a static interface method on an object

Static interface methods are called through the interface name, as in Shippable.format(9.5). Writing item.format(9.5) fails with illegal static interface method call.

Practice exercise

🏋️ Try it yourself

Create a Printable interface with an abstract method print() and a default method printCopies(int copies) that prints [1/2] and so on before each copy. Implement it in an Invoice class (number and total) and a BoardingPass class (passenger, flight and seat). Put one of each in a Printable[] array and print two copies of everything.

Show solution
public class PrintShop {
    public static void main(String[] args) {
        Printable[] queue = {
            new Invoice("INV-1042", 89.90),
            new BoardingPass("Ana Costa", "LH 401", "14C")
        };

        for (Printable p : queue) {
            p.printCopies(2);
        }
    }
}

interface Printable {
    void print();

    default void printCopies(int copies) {
        for (int i = 1; i <= copies; i++) {
            System.out.print("[" + i + "/" + copies + "] ");
            print();
        }
    }
}

class Invoice implements Printable {
    private String number;
    private double total;

    Invoice(String number, double total) {
        this.number = number;
        this.total = total;
    }

    @Override
    public void print() {
        System.out.printf("Invoice %s, total $%.2f%n", number, total);
    }
}

class BoardingPass implements Printable {
    private String passenger;
    private String flight;
    private String seat;

    BoardingPass(String passenger, String flight, String seat) {
        this.passenger = passenger;
        this.flight = flight;
        this.seat = seat;
    }

    @Override
    public void print() {
        System.out.println("Boarding pass: " + passenger + ", flight " + flight + ", seat " + seat);
    }
}
[1/2] Invoice INV-1042, total $89.90
[2/2] Invoice INV-1042, total $89.90
[1/2] Boarding pass: Ana Costa, flight LH 401, seat 14C
[2/2] Boarding pass: Ana Costa, flight LH 401, seat 14C

What's next?

Every class you've written, whether it extends something or not, secretly has one more parent: Object. It gives every object methods like toString() and equals(). Next, learn how to use and override them in the Java Object class.

Key takeaways

  • A Java interface is a contract: a list of methods that implementing classes promise to provide.
  • A class uses implements to sign the contract and must provide every abstract method as a public method.
  • A class can extend only one class but can implement many interfaces, separated by commas.
  • Interfaces can contain default methods (with a body), static methods (called on the interface) and constants (public static final).
  • Programming to an interface means using the interface as your variable and parameter type so any implementation fits.
  • Use an interface for a shared ability across unrelated classes and an abstract class for related classes sharing code and state.
  • A sealed interface (Java 17) lists exactly which classes may implement it with permits.

Frequently asked questions

What is an interface in Java?

An interface is a type that lists methods a class must provide, without saying how they work. A class implements the interface with the implements keyword and writes the method bodies itself.

Can a Java class implement more than one interface?

Yes. A class can implement any number of interfaces, for example class Drone implements Chargeable, Trackable. It can only extend one class, though.

What is a default method in a Java interface?

A default method is an interface method with a body, marked with the default keyword. Implementing classes inherit it automatically and can override it if they need different behavior.

Can an interface have variables in Java?

Only constants. Any field declared in an interface is automatically public, static and final, so it must be given a value and can never change.

What is the difference between an interface and an abstract class?

An interface describes a capability, has no instance fields or constructors, and a class can implement many. An abstract class describes a family, can have fields, constructors and any methods, and a class can extend only one.

Can you create an object of an interface?

No, new Chargeable() does not compile. You create objects of classes that implement the interface and can store them in variables of the interface type.