Definition
- Conflict: two unrelated interfaces with the same default method signature cause a compile error in the implementing class.
- Override required: the class must override the conflicting method with its own implementation.
- InterfaceName.super.method(): delegates to a specific interface's default implementation from within the override.
- Rule 1 (class wins): if a class defines a method, it beats all interface defaults.
- Rule 2 (sub-interface wins): if interface B extends interface A and both have the default, B's version wins because it is more specific.
- Rule 3 (must override): if two unrelated interfaces conflict, the class must override explicitly.
Rajesh's bank implements both RBI compliance and SEBI compliance rules. Both regulators define a default audit report format. The bank cannot use both simultaneously, so the compliance officer (implementing class) must explicitly choose: use RBI's format, use SEBI's format, or create a combined format that satisfies both. Non-conflicting rules from each regulator are followed automatically.
Understanding the Concepts
What happens with default method conflicts?
When a class implements two interfaces that both define a default method with the same signature, the compiler reports an error and the class must resolve the conflict.
How does the conflict occur?
package com.bank.compliance;
interface RBICompliant {
default String generateReport() {
return "RBI Standard Compliance Report";
}
}
interface SEBICompliant {
default String generateReport() { // SAME name and signature!
return "SEBI Standard Compliance Report";
}
}
// COMPILE ERROR! "class TradingBank inherits unrelated defaults"
// class TradingBank implements RBICompliant, SEBICompliant { }
How do you resolve the conflict?
package com.bank.compliance;
// Fix 1: own implementation
class TradingBankV1 implements RBICompliant, SEBICompliant {
@Override
public String generateReport() {
return "TradingBank Custom Compliance Report";
}
}
// Fix 2: delegate to ONE interface
class TradingBankV2 implements RBICompliant, SEBICompliant {
@Override
public String generateReport() {
return RBICompliant.super.generateReport(); // delegates to RBI
}
}
// Fix 3: combine BOTH
class TradingBankV3 implements RBICompliant, SEBICompliant {
@Override
public String generateReport() {
return RBICompliant.super.generateReport()
+ " | " + SEBICompliant.super.generateReport();
}
}
public class ConflictDemo {
public static void main(String[] args) {
System.out.println(new TradingBankV1().generateReport());
System.out.println(new TradingBankV2().generateReport());
System.out.println(new TradingBankV3().generateReport());
}
}
TradingBank Custom Compliance Report
RBI Standard Compliance Report
RBI Standard Compliance Report | SEBI Standard Compliance Report
What are the three resolution rules?
| Rule | Description | Example |
|------|-------------|--------|
| Rule 1: Class wins | A class method beats all interface defaults | Class defines generateReport, interface default is ignored |
| Rule 2: Sub-interface wins | More specific interface beats less specific | If B extends A and both have the default, B wins |
| Rule 3: Must override | Two unrelated interfaces conflict | Class must provide an explicit override |
package com.bank.compliance;
interface A { default String name() { return "A"; } }
interface B extends A { default String name() { return "B"; } }
class C implements A, B { }
// NO error! B.name() wins because B extends A (more specific)
// new C().name() returns "B"
What happens when a class defines its own method?
Rule 1 says the class always wins. If a class defines a method that matches a default method signature, the class version takes precedence.
package com.bank.compliance;
interface Auditable {
default String auditFormat() { return "Standard"; }
}
class BankService implements Auditable {
public String auditFormat() { return "Custom Bank Format"; }
}
// new BankService().auditFormat() returns "Custom Bank Format"
// The class method wins over the interface default.
What are common mistakes?
package com.bank.core;
// WRONG: forgetting to resolve the conflict
// class DualRegulatedBank implements RBICompliant, SEBICompliant { }
// Compile error: inherits unrelated defaults
// WRONG: trying to call super.method() without the interface name
// class BadBank implements RBICompliant, SEBICompliant {
// public String generateReport() {
// return super.generateReport(); // WRONG! super refers to class parent
// }
// }
// CORRECT: use InterfaceName.super.method()
class GoodBank implements RBICompliant, SEBICompliant {
@Override
public String generateReport() {
return RBICompliant.super.generateReport();
}
}
What about non-conflicting methods?
Methods that do not conflict are inherited normally from each interface with no override needed.
How is this different from C++ multiple inheritance?
Java's diamond problem is simpler than C++ because interfaces cannot have instance fields or constructors. The conflict is purely about method bodies, not state. Resolution is always explicit through overriding.
What should a senior engineer know?
The resolution rules are applied in order: class wins first, then sub-interface wins, then must-override. Understanding these rules helps design clean interface hierarchies. The best practice is to keep default methods small and focused on composition (and, andThen) or common patterns, avoiding complex business logic that is likely to conflict.
Visual Overview
Interface A Interface B
┌──────────────┐ ┌──────────────┐
│ default │ │ default │
│ generateReport│ │ generateReport│
└──────┬───────┘ └──────┬───────┘
│ │
└──────────┬─────────────┘
│
CONFLICT!
│
┌──────────▼───────────┐
│ Class C must │
│ override explicitly │
│ Options: │
│ 1. Own logic │
│ 2. A.super.method() │
│ 3. Combine both │
└──────────────────────┘
Resolution Priority:
1. Class method > interface default
2. Sub-interface > super-interface
3. Must override (unrelated interfaces)
Key Takeaway
When a class implements two interfaces that both define a default method with the same signature, the compiler forces the class to override the conflicting method. The class has three options: provide its own implementation, delegate to one interface's default using InterfaceName.super.method(), or combine both by calling both super defaults.
Java resolves default method conflicts using three priority rules. First, a class method always wins over an interface default. Second, a more specific sub-interface wins over a super-interface. Third, if neither rule applies (two unrelated interfaces), the implementing class must override. Non-conflicting methods from different interfaces are inherited normally.
In Rajesh's dual compliance service at National Bank of India, the TradingBank implements both RBICompliant and SEBICompliant. The bank resolves the generateReport conflict by combining both reports. Other non-conflicting methods from each regulator interface are inherited automatically.
Remember one sentence: two interfaces with the same default method force the class to override, and InterfaceName.super.method() delegates to the chosen interface.
---