Skip to content

Java Interfaces

In Java, an interface is a reference type, similar to a class, that defines a contract. It specifies a set of abstract methods that implementing classes must provide. Since Java 8, interfaces can also contain default methods, static methods, and even private methods (since Java 9).

Think of an interface like a blueprint for capabilities. A class implements an interface, promising to provide the functionality defined in that interface’s contract.

  • Cannot be instantiated directly.
  • Can contain abstract methods (no implementation, implicitly public abstract).
  • Can contain default methods (introduced in Java 8): Provide a default implementation that implementing classes inherit. This allows adding new methods to interfaces without breaking existing implementations.
  • Can contain static methods (introduced in Java 8): Utility methods associated with the interface itself, not with any implementing object.
  • Can contain private methods (introduced in Java 9): Helper methods for default or static methods within the interface.
  • Can contain public static final constants (fields). All fields are implicitly public, static, and final.
  • A class can implement multiple interfaces.
  • An interface can extend multiple other interfaces.
  • Achieve Abstraction: Hide implementation details, exposing only the necessary behavior.
  • Achieve Multiple Inheritance of Type: A class can implement multiple interfaces, inheriting different sets of capabilities.
  • Loose Coupling: Code depends on the interface contract, not specific implementations, making systems more flexible and maintainable.
  • Polymorphism: Objects can be treated as instances of an interface type they implement.
  • API Definition: Define clear contracts for libraries and frameworks.

Use the interface keyword to declare an interface. File name must match the interface name (e.g., Vehicle.java).

/* FileName: Vehicle.java */
/**
* Defines basic capabilities for vehicles.
*/
public interface Vehicle {
// Constant (implicitly public static final)
String TYPE = "Generic Vehicle";
// Abstract method (implicitly public abstract)
void startEngine();
void stopEngine();
// Default method (Java 8+)
default void honk() {
System.out.println("Beep beep!");
log("Honk executed"); // Using private helper method
}
// Static method (Java 8+)
static void displayType() {
System.out.println("This is a type of: " + TYPE);
}
// Private method (Java 9+) - Helper for default/static methods
private void log(String message) {
System.out.println("LOG: " + message);
}
}

A class uses the implements keyword to implement one or more interfaces. If a class implements an interface but does not provide an implementation for all abstract methods, the class itself must be declared abstract.

Use the @Override annotation when implementing interface methods for compile-time checks and clarity.

/* FileName: Car.java */
public class Car implements Vehicle {
private boolean engineRunning = false;
@Override
public void startEngine() {
engineRunning = true;
System.out.println("Car engine started.");
}
@Override
public void stopEngine() {
engineRunning = false;
System.out.println("Car engine stopped.");
}
// Optional: Override the default method
@Override
public void honk() {
System.out.println("HONK HONK! (Car specific)");
}
public boolean isEngineRunning() {
return engineRunning;
}
public static void main(String[] args) {
// Using the static method from the interface
Vehicle.displayType();
Car myCar = new Car();
myCar.startEngine();
myCar.honk(); // Calls the overridden honk method
myCar.stopEngine();
// Polymorphism: Treat Car as a Vehicle
Vehicle anotherVehicle = new Car();
anotherVehicle.startEngine();
// anotherVehicle.isEngineRunning(); // Error: isEngineRunning() is not in Vehicle interface
// Example using the default honk if not overridden
Vehicle bike = new Motorbike(); // Assuming Motorbike implements Vehicle but doesn't override honk
bike.startEngine();
bike.honk(); // Calls the default honk() from Vehicle interface
bike.stopEngine();
}
}
// Assume Motorbike class exists and implements Vehicle without overriding honk
/*
class Motorbike implements Vehicle {
@Override
public void startEngine() { System.out.println("Motorbike engine started."); }
@Override
public void stopEngine() { System.out.println("Motorbike engine stopped."); }
}
*/
  • A class must implement all abstract methods defined in the interface(s) it implements, or the class must be declared abstract.
  • The implementing method must have the same signature (name, parameter types) and a compatible return type (same or a subtype).
  • The implementing method cannot have a more restrictive access modifier (e.g., if the interface method is public, the implementation must also be public).
  • Use the @Override annotation.
  • A class can implement multiple interfaces by listing them after the implements keyword, separated by commas (e.g., class MyClass implements InterfaceA, InterfaceB).

An interface can inherit from other interfaces using the extends keyword. This allows creating hierarchies of interfaces. A child interface inherits all abstract methods, default methods, static methods, and constants from its parent interface(s).

// Filename: ElectricVehicle.java
public interface ElectricVehicle extends Vehicle { // Extends Vehicle
void charge();
int getBatteryLevel();
}
// Filename: Autonomous.java
public interface Autonomous {
void driveAutonomously();
}
// Filename: AutonomousElectricCar.java
// Implementing class needs to implement methods from ElectricVehicle, Vehicle, and Autonomous
public class AutonomousElectricCar implements ElectricVehicle, Autonomous {
@Override
public void startEngine() { /* Implementation */ System.out.println("Electric motor started."); }
@Override
public void stopEngine() { /* Implementation */ System.out.println("Electric motor stopped."); }
@Override
public void charge() { /* Implementation */ System.out.println("Charging..."); }
@Override
public int getBatteryLevel() { /* Implementation */ return 85; }
@Override
public void driveAutonomously() { /* Implementation */ System.out.println("Driving autonomously."); }
// It can still use default/static methods from Vehicle, e.g., honk()
}

With the addition of default methods, interfaces can provide implementation, blurring the lines with abstract classes. However, key differences remain:

  • Multiple Inheritance: A class can implement multiple interfaces but extend only one abstract class.
  • State (Instance Variables): Abstract classes can have instance variables (state), while interfaces traditionally cannot (only public static final constants).
  • Constructors: Abstract classes can have constructors, interfaces cannot.
  • Purpose: Use an abstract class when you want to provide a common base implementation and state for a group of related subclasses (an “is-a” relationship). Use an interface when you want to define a contract or capability that various, possibly unrelated, classes can implement (a “has-a” or “can-do” relationship).

A functional interface is an interface that contains exactly one abstract method (though it can have multiple default or static methods). They are crucial for enabling functional programming in Java using lambda expressions and method references (e.g., Runnable, Comparator, ActionListener).

The @FunctionalInterface annotation can be used to indicate this intent and allow the compiler to verify it.

@FunctionalInterface
interface MyFunctionalInterface {
void execute(); // Single abstract method
default void print() {
System.out.println("Printing from functional interface.");
}
}
// Usage with Lambda:
MyFunctionalInterface runner = () -> System.out.println("Executing lambda.");
runner.execute(); // Output: Executing lambda.
runner.print(); // Output: Printing from functional interface.

Explore the Java documentation for core interfaces like List, Map, Set, Comparable, Runnable, and Callable to see practical examples.