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.
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'
}
β 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)
}
}
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();
}
}
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.
}
β 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();
}
}
π§ 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).

Top comments (0)