Diamond conflicts in Java
Two defaults with the same signature must be resolved with X.super.m().
Cat or dog?
Both interfaces bring a default sound(). What happens?
interface Cat {
default String sound() { return "meow"; }
}
interface Dog {
default String sound() { return "woof"; }
}
class CatDog implements Cat, Dog { }
void main() {
System.out.println(new CatDog().sound());
}meowwoofCompile error
Show the answer
Compile error. Neither default is more specific than the other, so any choice would be arbitrary. Java refuses to guess and forces CatDog to decide.
You break the tie
Override the method in your class. Inside, pick a version with **InterfaceName.super.method()** — or combine several. Calling Dog.super.sound() + Cat.super.sound() returns woofmeow, in exactly the order you write them.
class CatDog implements Cat, Dog {
public String sound() {
return Cat.super.sound();
}
}Plain super is the wrong door
super.sound() does NOT mean "one of my interfaces". Plain super means the superclass — here Object — which has no sound(). To reach an interface's default, name it: Cat.super.sound().
public String sound() {
return super.sound(); // error
}Rule 1: the class wins
No conflict arises when a superclass already provides the method: a method inherited from a class always beats an interface default. And when one interface extends another and overrides its default, the more specific (sub-)interface wins.
class Base {
public String name() { return "class"; }
}
class Kid extends Base implements Named { }
// Kid's name() comes from BaseClass versus interface
Lamp offers a default, Light (a class) has a real method. What prints?
interface Lamp {
default String color() { return "blue"; }
}
class Light {
public String color() { return "red"; }
}
class Neon extends Light implements Lamp { }
void main() {
System.out.println(new Neon().color());
}redblueCompile error
Show the answer
Class wins. Neon inherits color() from its superclass Light, which beats Lamp's default. No conflict is reported.
When upgrades collide
This bites real projects: you implement interfaces from two libraries, and after an upgrade both ship a default method with the same signature. Your code suddenly stops compiling. The fix takes three lines: override the method and delegate with X.super.m().
Key takeaways
- Two inherited defaults with the same signature → compile error until you override
- Pick a version with A.super.m(), or combine several
- 'Class wins': a method from a superclass beats any interface default
- A sub-interface's default beats the one it overrides
The "diamond problem" is named after the diamond shape of its inheritance diagram. Because interfaces carry no instance fields, Java's diamonds can only clash over methods — never over state.
Practice questions
What does this print?
interface A { default String hi() { return "A"; } }
interface B { default String hi() { return "B"; } }
class C implements A, B { }
void main() {
System.out.println(new C().hi());
}- A
- B
- Compile error
- AB
Check your answer
Compile error. C inherits two unrelated defaults with the same signature, so the compiler reports a conflict until C overrides hi().
Inside C.hi(), you want to call interface A's default version. What fills the blank?
class C implements A, B {
public String hi() {
return ___.hi();
}
}- A.super
- super.A
- A.this
- super
Check your answer
A.super. `A.super.hi()` invokes the default from the directly implemented interface A. Plain super would mean the superclass (Object).