How does Java resolve a conflict when a class inherits the same default method from two interfaces, and how does this compare to inheriting from a class?
answer
- classes win over interface defaults
- more-specific sub-interface beats super-interface
- unrelated tie -> programmer must override
- disambiguate with InterfaceName.super.method()
- single class inheritance = no diamond by construction
basics
~20 sIf two interfaces give the same default method, Java won't pick for you — the class must override that method, and inside it can call a chosen one with InterfaceName.super.method(). With classes there's only one superclass, so no such conflict arises.
solid answer
~50 sDefault methods reintroduced a limited 'diamond problem': a class can implement two interfaces that each provide a default method with the identical signature. Java refuses to silently choose and gives a compile error unless the class overrides the method to disambiguate; inside the override it can delegate with `A.super.greet()` to pick a specific inherited version. Two precedence rules apply first: (1) a concrete method from a superclass beats any interface default ('classes win'), and (2) a more specific sub-interface's default beats its super-interface's. Only when two unrelated interfaces tie does the programmer-must-resolve rule kick in. Single class inheritance can't produce this because there's exactly one chain of superclasses, so any inherited concrete method has a unique most-specific source. This is one reason Java permits multiple inheritance of type (interfaces) but not of implementation state (classes): defaults add behavior but the language still forces explicit conflict resolution to keep dispatch unambiguous.
code
java · 15 linesinterface A { default String who() { return "A"; } }
interface B { default String who() { return "B"; } }
// Two UNRELATED defaults -> won't compile without an override:
class C implements A, B {
@Override
public String who() {
// must disambiguate explicitly; pick one (or combine):
return A.super.who() + "+" + B.super.who(); // "A+B"
}
}
// 'Classes win': a superclass method overrides any interface default
class Base { public String who() { return "Base"; } }
class D extends Base implements A { } // compiles; D.who() returns "Base", not "A"go deeper
Aware that two interfaces can provide a method with the same name and that the class then has to override it; may not know the precedence rules.
States the override-and-disambiguate requirement and the Interface.super.method() syntax, and knows single class inheritance avoids the conflict.
Recites the full precedence order (classes win, more-specific interface wins, else programmer resolves) and explains why Java allows multiple type inheritance but not implementation inheritance to keep dispatch deterministic.
Reasons about API evolution risks: defaults silently shadowed by 'classes win', source/binary compatibility of adding defaults, and how multiple-default composition interacts with library upgrades and versioning.
## Setup: what's a default method Since Java 8, an interface method may carry an implementation if marked `default`: `default String greet() { return "hi"; }`. Implementers inherit it for free and may override it. Because a class can implement *many* interfaces, it can now inherit *behavior* from several sources — which raises the classic **diamond problem**. ## The diamond problem The name comes from a diamond-shaped inheritance graph: a type `D` inherits from two types `B` and `C` that both inherit from a common `A`, and `B` and `C` each define the same method differently. Which one does `D` get? In languages with full multiple inheritance of implementation this is genuinely ambiguous. Java sidesteps it for *classes* by allowing only **single** class inheritance — there's always one linear chain of superclasses, so any inherited concrete method has a single most-specific definition. Default methods reopened a *bounded* version of the problem: a class `D implements B, C` where `B` and `C` are unrelated interfaces that both declare `default void m()`. Now there are two competing bodies and no linear order between `B` and `C`. ## Java's resolution rules (in order) The compiler applies three rules: 1. **Classes win over interfaces.** If a *superclass* provides a concrete `m()`, that implementation is used and any interface default `m()` is ignored. Instance state and class implementation take priority over interface defaults. 2. **More-specific interface wins.** If one interface *extends* the other (`B extends A`) and both have a default `m()`, the sub-interface's (`B`'s) version wins because it is more specific. 3. **Otherwise the programmer must resolve.** If two interfaces are unrelated (neither extends the other) and both supply a default `m()`, the compiler reports an error: *'inherits unrelated defaults for m() from types B and C'*. The class is **forced to override** `m()`. Inside that override it may delegate to a chosen inherited version using the special syntax `B.super.m();` (qualified super). It can also write entirely new behavior, or combine both. ## The disambiguation syntax `InterfaceName.super.method(args)` is how you invoke a *specific* interface's default implementation from the overriding method. `super.method()` alone would be ambiguous, so Java requires you to name the interface. ## Why this differs from class inheritance With `extends` you have exactly one parent and one upward chain, so method resolution is a single, ordered search up that chain — there is never a tie between two equally-specific sources. That's the whole reason Java chose **single inheritance of implementation**: it keeps method dispatch deterministic and avoids the unbounded diamond. Interfaces were allowed in multiples because, *before* defaults, they carried no implementation to conflict. Default methods added behavior but the designers deliberately kept the *forced-resolution* rule so the language never silently guesses, preserving predictable dispatch. ## Practical implications - Conflicts are rare in practice but appear when composing interfaces from different libraries; the fix (override + qualified super) is mechanical. - The 'classes win' rule means adding a default method to an interface can be silently shadowed by an existing superclass method — worth knowing when evolving APIs. - A constant (static final field) name clash between interfaces is a *different* issue: referencing it ambiguously is a compile error you resolve by qualifying with the interface name; it isn't dispatch. In short: Java permits multiple inheritance of *type and default behavior* but guarantees unambiguous dispatch by (a) letting class implementations and more-specific interfaces win automatically, and (b) forcing an explicit override when two unrelated defaults tie.
- If a superclass has a concrete method and an implemented interface has a default with the same signature, which runs?The superclass's concrete method — the 'classes win over interfaces' rule. The interface default is ignored. This means adding a default to an interface can be silently shadowed by an inherited class method, which matters when evolving APIs.
- Does the same conflict-resolution apply to constants declared in two interfaces?No — that's not method dispatch. If both interfaces declare a public static final field with the same name, referencing the bare name is an ambiguity compile error, resolved by qualifying it with the interface name (A.X vs B.X). Constants don't have the 'classes win' / 'override-to-resolve' machinery.
saying these in an interview costs you the question
- Saying Java silently picks one default method automatically for unrelated interfaces — it errors and forces an override.
- Using plain super.method() to disambiguate; you must write Interface.super.method().
- Claiming interface defaults override a superclass concrete method — it's the reverse (classes win).
- Asserting Java has no diamond problem at all — it has a bounded one for default methods and resolves it explicitly.
- Confusing a constant-name clash (qualify-to-resolve) with default-method dispatch.