DEV Community

Cover image for The Diamond Problem in JAVA πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž
MD ASHRAF
MD ASHRAF

Posted on

The Diamond Problem in JAVA πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž πŸ’Ž

The Diamond Problem is an ambiguity issue in multiple inheritance where a class inherits the same method from two or more parent classes. Java prevents this with classes, but it can arise with interfaces (since Java 8) if a class implements two interfaces that provide a default method with the same signature.

Problem diagram

Code example:

// Interface 1
interface InterfaceA {
    default void sameMethod() {
        // some functionality
        System.out.println("Implementation from Interface A");
    }
}

// Interface 2
interface InterfaceB {
    default void sameMethod() {
        // some functionality
        System.out.println("Implementation from Interface B");
    }
}

// Class D implements both interfaces, causing the Diamond Problem
// This code will result in a **COMPILATION ERROR

class ClassD implements InterfaceA, InterfaceB {
    // Compile-time error:
    // 'ClassD inherits unrelated defaults for sameMethod() from types InterfaceA and InterfaceB'
}
Enter fullscreen mode Exit fullscreen mode

βœ… The Solution (After Resolution)

Java resolves the Diamond Problem by forcing the implementing class to provide its own version of the ambiguous method. This is Java's rule for default method ambiguity: when there's a conflict, the implementing class must override the method.

Code example:

// Interface 1 (Same as before)
interface InterfaceA {
    default void sameMethod() {
        System.out.println("Implementation from Interface A");
    }
}

// Interface 2 (Same as before)
interface InterfaceB {
    default void sameMethod() {
        System.out.println("Implementation from Interface B");
    }
}

// Class D resolves the Diamond Problem by providing its own implementation
class ClassD implements InterfaceA, InterfaceB {

    // Must override the ambiguous method
    @Override
    public void sameMethod() {
        // Option 1: Provide a brand new implementation
        System.out.println("Implementation from Class D (Resolving conflict)");
    }
}

public class DiamondProblemDemo {
    public static void main(String[] args) {
        ClassD obj = new ClassD();
        obj.sameMethod(); // Output: Implementation from Class D (Resolving conflict)
    }
}
Enter fullscreen mode Exit fullscreen mode

Here child class have provided its own implementation, but suppose sometimes we want to use the implementation already defined in one of the interface above then we can bring that implememntation inside child class **overridden method **using

// Option 2 (Advanced): Call a specific interface's default method
// **InterfaceA.super.sameMethod()**;

Code example:

// Class D resolves the Diamond Problem by providing its own implementation
class ClassD implements InterfaceA, InterfaceB {

    // Must override the ambiguous method
    @Override
    public void sameMethod() {
        // Option 1: Provide a brand new implementation
        System.out.println("Implementation from Class D (Resolving conflict)");

        // Option 2 (Advanced): Call a specific interface's default method
        // InterfaceA.super.sameMethod();
    }
}
Enter fullscreen mode Exit fullscreen mode

Lets explore more deeper

If InterfaceA extends two other interfaces (InterfaceX and InterfaceY), and both InterfaceX and InterfaceY have a default method with the same signature, the ambiguity is solved at which level?

Answer: At the level of InterfaceA itself.

The rule is: A class or interface always wins over a default method from a super-interface.

Code Example problem:

interface InterfaceX {
    default void sameMethod() {
        System.out.println("From X");
    }
}

interface InterfaceY {
    default void sameMethod() {
        System.out.println("From Y");
    }
}

// THIS WILL RESULT IN A COMPILATION ERROR!
// Interface A inherits unrelated defaults for sameMethod() from types InterfaceX and InterfaceY.
// It must explicitly override sameMethod().
interface InterfaceA extends InterfaceX, InterfaceY {
    // Error occurs here because Java doesn't know whether A should use X's or Y's version.
}

class ClassD implements InterfaceA {
    // This class won't even compile because InterfaceA has an error.
}
Enter fullscreen mode Exit fullscreen mode

βœ… Resolution (Required Override in InterfaceA)

To fix this, InterfaceA must provide an implementation for sameMethod(). It can use one of the parent implementations or define a new one.

interface InterfaceX {
    default void sameMethod() {
        System.out.println("From X");
    }
}

interface InterfaceY {
    default void sameMethod() {
        System.out.println("From Y");
    }
}

// RESOLUTION: InterfaceA provides an override.
interface InterfaceA extends InterfaceX, InterfaceY {
    @Override
    default void sameMethod() {
        // InterfaceA chooses which method to use, or provides its own.
        // Here, it chooses to call the implementation from InterfaceX.
        InterfaceX.super.sameMethod();
        System.out.println("...via A's resolution.");

        // 2. Explicitly call Interface Y's implementation
        InterfaceY.super.sameMethod();
    }
}

// Class D can now implement InterfaceA without error
class ClassD implements InterfaceA {
    // Class D doesn't need to do anything, as InterfaceA has already provided the concrete method.
}

public class DiamondProblemDeepDive {
    public static void main(String[] args) {
        ClassD obj = new ClassD();
        obj.sameMethod();
    }
}
Enter fullscreen mode Exit fullscreen mode

🧠Summary of Hierarchy Rules

Class always wins: A method defined in a class (like ClassD) is always chosen over a default method in any interface.

Sub-interface wins over super-interface: A default method in a sub-interface (like InterfaceA overriding the method) is always chosen over a default method in a super-interface (InterfaceX or InterfaceY).

Conflict = Mandatory Override: If an interface or class inherits two or more conflicting default methods from its immediate parents, it must provide an explicit override (either by defining a new body or by using the InterfaceName.super.methodName() syntax).

Thank you, PLease Subscribe like and bookmark our more series here .

HTML & CSS Series
Javascript Series
Angular Series

Top comments (0)