The Diamond Problem
Imagine a child who inherits a house from the mother's side and a different house at the same address from the father's side. Which one does the child live in? Programming languages hit the same puzzle when a class inherits from two parents that both define the same method. Because the class diagram looks like a diamond, it's called the diamond problem, and it's the reason Java allows only one parent class.
The Diamond
If Java allowed class Copier extends Printer, Scanner, and both parents had their own start(), then copier.start() would be ambiguous. Worse, if both parents had a field status, would Copier have one copy or two? C++ needs extra rules (virtual inheritance) to answer that. Java's designers chose simplicity: one parent class, so a class's method and field come from exactly one chain.
Interfaces Can Still Meet in a Diamond
Since Java 8, interfaces can have default methods with code. A class can implement many interfaces, so two defaults with the same signature can clash. Java doesn't guess: the code doesn't compile until you decide.
Diamond.java:3: error: types Printer and Scanner2 are incompatible;
class Combo implements Printer, Scanner2 {}
^
class Combo inherits unrelated defaults for greet() from types Printer and Scanner2Resolving the Clash
The class overrides the method and, if it wants, calls a chosen parent's version with InterfaceName.super.method():
public class Office {
interface Printer {
default String start() { return "Printer warming up"; }
}
interface Scanner {
default String start() { return "Scanner calibrating"; }
}
static class Copier implements Printer, Scanner {
@Override
public String start() {
return Printer.super.start() + " and " + Scanner.super.start();
}
}
public static void main(String[] args) {
System.out.println(new Copier().start());
}
}Printer warming up and Scanner calibratingHow it works
- Both interfaces offer a default
start(). Copiermust overridestart()(lines 11 to 14), or the code doesn't compile.Printer.super.start()calls Printer's default;Scanner.super.start()calls Scanner's. The class chooses explicitly, so nothing is ambiguous.
interface and default methods are covered fully in "Interfaces in Java" and "Default, Static and Private Methods in Interfaces".
Try it yourself: make start() return only Scanner.super.start(). What prints now?
The Rules Java Uses
When a class inherits a method from several places, Java applies these rules in order:
| Rule | Meaning |
|---|---|
| 1. Classes win | A method from the superclass beats any interface default |
| 2. More specific interface wins | If interface B extends A, B's default beats A's |
| 3. Otherwise, you must choose | Override the method; call X.super.method() if you want one of them |
Common Mistakes
Saying Java has no multiple inheritance at all. It has multiple inheritance of type (interfaces) and, through default methods, of behavior; not of classes or state.
Calling super.start() in the copier. With two interfaces, plain super is ambiguous; name the interface: Printer.super.start().
Ignoring the compile error by removing an interface. Often the right fix is a deliberate override.
Interview Corner
What is the diamond problem, and how does Java handle it?
When a class inherits from two parents that both inherit or define the same method, it's unclear which version the class gets. Java avoids it for classes by allowing only one superclass. For interfaces with conflicting default methods, Java reports a compile error and requires the class to override the method, optionally calling a specific one with InterfaceName.super.method().
Why does Java support multiple inheritance through interfaces but not classes?
Interfaces carry no instance state, so there's no question of duplicated fields, and any method clash is resolved explicitly by the implementing class. Classes carry state and constructors, which makes multiple inheritance complex and error-prone.
Practice
- Easy: Draw the diamond for
Animal,Bird,Fishand an imaginaryFlyingFish extends Bird, Fish. Which method could clash? - Harder: Create interfaces
WifiandBluetooth, each with a defaultconnect(), and a classPhoneimplementing both that connects to Wi-Fi first and then Bluetooth.
Key Takeaways
Was this tutorial helpful?