Default methods in Java
Interface methods with a body; enable API evolution.
Plugin interface. You need to add one new method. Add it the normal way and you break every single one of them. Now what?The upgrade problem
Adding a new abstract method to a published interface breaks every class that implements it: none of them has the new method, so none of them compiles. Turning the interface into an abstract class breaks them too. Java needed a third option.
interface Plugin {
String name();
String version(); // breaks everyone!
}default = a method with a body
Since Java 8, an interface method marked **default has a body. Implementing classes inherit it for free**. A default may call the interface's abstract methods — at runtime they dispatch to the real class's version.
interface Greeter {
String name();
default String greet() {
return "Hi " + name();
}
}Inherited for free
Bot implements the Greeter from the previous screen but writes only name(). What prints?
class Bot implements Greeter {
public String name() { return "R2"; }
}
void main() {
System.out.println(new Bot().greet());
}Hi R2Hi nullCompile error: Bot must implement greet()
Show the answer
Bot inherits greet(). Inside it, name() runs Bot's implementation, giving Hi R2. No compile error: defaults already have a body.
Keep it or replace it
A class may override a default like any other method. Calls dispatch on the real object, so Circle's version runs even through a Shape variable: this prints circle.
interface Shape {
default String label() { return "shape"; }
}
class Circle implements Shape {
public String label() { return "circle"; }
}
Shape s = new Circle();
s.label(); // "circle"No fields to play with
A default method can't read or update instance fields of the interface — interfaces have none (any field is a static final constant). Defaults can only work through other methods, such as abstract getters that the implementing class provides.
How Java 8 upgraded the world
Java 8 added forEach to Iterable, and stream() and removeIf to Collection, as default methods. Every collection class ever written — including third-party ones — got them overnight without a single line changed. Library authors use the same trick to grow APIs safely.
Key takeaways
- default String greet() { ... } has a body inside the interface
- Implementers inherit it and can override it
- Defaults may call the interface's abstract methods
- Defaults can't use instance fields — interfaces have none
💡 A rental car arrives with standard seat settings: you can keep them or adjust them.
Map.getOrDefault is a default method on the Map interface — and HashMap overrides it with its own faster version. Defaults are a safe baseline, not a cage.
Practice questions
What does this print?
interface Greeter {
String name();
default String greet() { return "Hi " + name(); }
}
class Bot implements Greeter {
public String name() { return "Bot"; }
}
void main() {
System.out.println(new Bot().greet());
}- Hi Bot
- Hi null
- Compile error: Bot must implement greet()
- Hi Greeter
Check your answer
Hi Bot. Bot inherits greet() from the interface. Inside it, name() dispatches to Bot's implementation, producing "Hi Bot".
What does this print?
interface Shape {
default String label() { return "shape"; }
}
class Circle implements Shape {
public String label() { return "circle"; }
}
void main() {
Shape s = new Circle();
System.out.println(s.label());
}- circle
- shape
- shape circle
- Compile error
Check your answer
circle. Circle overrides the default. Calls are dispatched on the real object, so Circle's version runs even through a Shape variable.