The Diamond Problem

Naveen AnamaneniUpdated · 5 min read

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

Two inherited versions of start(): which one runs?

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.

Compiler output
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 Scanner2

Resolving the Clash

The class overrides the method and, if it wants, calls a chosen parent's version with InterfaceName.super.method():

Office.java▶ Try it
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());
    }
}
Output
Printer warming up and Scanner calibrating

How it works

  1. Both interfaces offer a default start().
  2. Copier must override start() (lines 11 to 14), or the code doesn't compile.
  3. 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:

RuleMeaning
1. Classes winA method from the superclass beats any interface default
2. More specific interface winsIf interface B extends A, B's default beats A's
3. Otherwise, you must chooseOverride 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

  1. Easy: Draw the diamond for Animal, Bird, Fish and an imaginary FlyingFish extends Bird, Fish. Which method could clash?
  2. Harder: Create interfaces Wifi and Bluetooth, each with a default connect(), and a class Phone implementing both that connects to Wi-Fi first and then Bluetooth.

Quick check: Diamond problem

4 questions
1What is the diamond problem?
2How does Java avoid it for classes?
3A class implements two interfaces with the same default method. What happens?
4How do you call Printer's default start() from the overriding method?

Key Takeaways

Was this tutorial helpful?

Lesson 114 of 482