Unit 3 · OOP Concepts

3.5.3Multiple inheritance and the diamond problem

The problem

If class D inherits from both B and C, and both inherit a method show() from A and override it differently, then D does not know which show() to use. This is the diamond problem. Java avoids it by allowing a class to extend only one class but implement many interfaces.

Ashow()Bshow() { "B" }Cshow() { "C" }Dd.show() ?Java forbids extending two classes; a class may implement many interfaces
The diamond problem: if B and C override show() differently, which version does D inherit?
Java
interface Flyable { void fly(); }
interface Swimmable { void swim(); }

class Duck extends Animal implements Flyable, Swimmable {
    Duck(String name) { super(name); }
    public void fly()  { System.out.println(name + " flies"); }
    public void swim() { System.out.println(name + " swims"); }
}

How the Duck example avoids the problem

Duck extends only one class, Animal, so it inherits code (the name attribute and the constructor) from exactly one place. From the two interfaces it inherits only promises: Flyable promises a fly() method and Swimmable promises a swim() method. Duck writes the bodies itself, so there is never any doubt about which code runs. A Duck can be used wherever an Animal, a Flyable or a Swimmable is expected:

Java
Duck d = new Duck("Donald");
Flyable f = d;      // a Duck is Flyable
Swimmable s = d;    // and Swimmable
f.fly();            // Donald flies
s.swim();           // Donald swims

What if two interfaces have the same default method?

Since Java 8, interfaces can contain default methods, with a body. If a class implements two interfaces that both supply the same default method, the diamond problem could come back. Java refuses to guess: the class must override the method, and can choose a version with InterfaceName.super.method():

Java
interface Camera { default String info() { return "Camera"; } }
interface Phone  { default String info() { return "Phone"; } }

class SmartPhone implements Camera, Phone {
    @Override
    public String info() {
        return Phone.super.info() + " with " + Camera.super.info();
    }
}
// new SmartPhone().info() returns "Phone with Camera"

How other languages handle it

Remember

  • The diamond problem: two parents provide different versions of the same method, and it is unclear which one the child inherits.
  • Java: extend one class, implement many interfaces.
  • If two interfaces provide the same default method, the class must override it.