Skip to main content

Default & Static Methods

Before Java 8, an interface was a strict contract: it could only contain abstract method signatures (methods without a body) and constant variables (public static final). If a class implemented an interface, it was forced to provide an implementation for every single method defined in that interface.

Java 8 completely broke this rule by introducing Default Methods and Static Methods in interfaces.


Why were Default Methods added?

The Java architects faced a massive problem when designing Java 8. They wanted to add the revolutionary stream() method to the Collection interface so developers could easily stream Lists and Sets.

The Problem: If they added a new abstract method stream() to the Collection interface, every single class in the world that implemented Collection would instantly break and fail to compile, because those classes didn't have an implementation for stream(). It would break millions of applications globally.

The Solution: The default keyword.

By adding a default implementation of stream() directly inside the interface, the old classes were not forced to implement it. They simply inherited the default behavior, maintaining perfect backward compatibility!


1. Default Methods

A default method is a method inside an interface that has a body. You use the default keyword to declare it.

public interface Vehicle {
// A traditional abstract method (must be implemented by classes)
void startEngine();

// A default method (has a body, optional to override)
default void turnOnAlarm() {
System.out.println("BEEP! BEEP! BEEP! Alarm activated.");
}
}

Using Default Methods

When a class implements this interface, it must implement startEngine(), but it inherits turnOnAlarm() for free!

public class Car implements Vehicle {

@Override
public void startEngine() {
System.out.println("Vroom!");
}

// We don't have to implement turnOnAlarm(), we just get it!
}

public class LabDefaultMethod1 {

public static void main(String[] args) {
Car myCar = new Car();

myCar.startEngine(); // Output: Vroom!

// Calling the default method inherited from the interface!
myCar.turnOnAlarm(); // Output: BEEP! BEEP! BEEP! Alarm activated.
}
}

The Diamond Problem (Multiple Inheritance)

Java classes cannot extend multiple classes, but they can implement multiple interfaces. What happens if two interfaces have a default method with the exact same name?

interface Camera {
default void turnOn() {
System.out.println("Camera ON");
}
}

interface Radio {
default void turnOn() {
System.out.println("Radio ON");
}
}

// The compiler throws an ERROR here! It doesn't know which turnOn() to inherit.
public class SmartPhone implements Camera, Radio {

// To fix it, you MUST override the method and explicitly choose one (or write new logic)
@Override
public void turnOn() {
// We choose to use the Camera's default method
Camera.super.turnOn();
}
}

2. Static Methods in Interfaces

Java 8 also allowed static methods inside interfaces.

Just like static methods in classes, they belong to the interface itself, not to the instances of the classes that implement the interface. They are primarily used to provide utility or helper methods directly within the interface, eliminating the need to create separate utility classes (like Collections vs Collection).

public interface MathUtils {
// A static helper method inside an interface
static int add(int a, int b) {
return a + b;
}
}

public class LabStaticMethod1 {

public static void main(String[] args) {
// You call the static method using the Interface name directly
int sum = MathUtils.add(5, 10);
System.out.println("Sum: " + sum); // Output: Sum: 15
}
}