22. Interfaces with Default and Static Methods
Since Java 8, interfaces can have default methods (inherited implementations) and static methods; Java 9 added private methods โ enabling rich mixin-style abstractions and backwards-compatible API evolution.
Explanation
default methods provide a method body inside an interface. Implementing classes inherit the default unless they override it. This allows API evolution: you can add a default method to an existing interface without breaking all existing implementors (they get the default for free).
static interface methods belong to the interface itself (not instances) and cannot be inherited or overridden. They're useful for factory methods and utilities tied to the interface type (List.of(), Comparator.comparing()).
Diamond problem with defaults: if a class implements A, B and both A and B declare default void foo(), the compiler reports an error and requires the class to explicitly override foo(). If a class inherits from both a superclass and an interface that both define foo(), the superclass method always wins (class wins over interface default).
Example
import java.util.List;
import java.util.Comparator;
public class InterfaceDefaultMethods {
interface Greeter {
String greet(String name); // abstract
default String greetLoudly(String name) { // default
return greet(name).toUpperCase();
}
static Greeter formal() { // static factory
return name -> "Good day, " + name + ".";
}
}
interface Farewell {
default String farewell(String name) { return "Goodbye, " + name; }
}
// Diamond problem: both have farewell โ must override
interface Greeter2 extends Greeter, Farewell {
// Must override to resolve ambiguity if two defaults conflict
}
public static void main(String[] args) {
Greeter casual = name -> "Hey, " + name + "!";
System.out.println(casual.greet("Alice")); // Hey, Alice!
System.out.println(casual.greetLoudly("Alice")); // HEY, ALICE!
Greeter formal = Greeter.formal(); // static method
System.out.println(formal.greet("Bob")); // Good day, Bob.
// Comparator.comparing โ chained static + default methods
List<String> names = List.of("Charlie", "Alice", "Bob");
names.stream()
.sorted(Comparator.comparing(String::length)
.thenComparing(Comparator.naturalOrder()))
.forEach(System.out::println);
}
}Sources
- https://openjdk.org/jeps/126 โ JEP 126: Lambda Expressions & Virtual Extension Methods
- https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html โ Default methods tutorial