Topic 65 of 119 6. Object-Oriented Programming in Java Interactive Tutorial

Interfaces in Java: Contracts, Multiple Inheritance, and Default Methods

17 mins read Last updated: 22 Aug 2026 26,245 views

Direct Answer & Core Concept

An interface is a contract that says what a type must be able to do without saying how, or what it stores. Interface methods are implicitly public abstract and interface fields are implicitly public static final, which is why none of those keywords are ever written:
Main.java
Run Online
interface Payable {
    int CURRENCY = 840;
    // implicitly public static final
    void pay(long amount);
    // implicitly public abstract
    String currency();
}

A class may implement any number of interfaces, so an object can advertise several unrelated capabilities at once. That is multiple inheritance of type rather than of state: nothing is inherited that stores data, so the C++ diamond problem has no equivalent here.

Before Java 8 this created a real trap. Adding a method to an interface meant every existing implementor had to be updated, and any one missed was a compile error. A default method fixed that by arriving with an implementation:

Main.java
Run Online
interface Auditable {
    long amountOf();
    default String auditTrail() {
        return "amount " + amountOf();
    }
}

Overriding is now optional. Implementors that want different behaviour override the method; the rest inherit a working fallback untouched. This is how Iterable.forEach and Collection.removeIf were added to the JDK without breaking a single downstream class.

One subtlety is worth knowing up front. When a class can inherit competing defaults, javac resolves them in a fixed order: a method on the class wins, then the most specific interface wins, and if two unrelated interfaces both declare it the compiler refuses to guess. You break that tie yourself, either by overriding the method or by delegating to one parent with A.super.go().

Java 8 also added static methods for interface-level utilities, and Java 9 added private methods so default methods can share helpers without widening the public contract. Choose an interface to declare a capability; choose an abstract class when the subtypes need shared state or a shared workflow.

Detailed Explanation & Mechanics

1) An Interface Is a Contract, Not a Base Class

An interface describes what a type must be able to do, and nothing about how it stores or computes anything. It holds no instance state and no constructor, so you cannot create an object of an interface any more than you can create one of an abstract class.

Main.java
Run Online
interface Payable {
    int CURRENCY = 840;
    long amountOf();
    String currency();
    void pay(long amount);
}

None of those modifiers are written, because every one of them is implied. Reflection confirms what the compiler actually stores:

Main.java
Run Online
Method m = Payable.class.getMethod("currency");
Modifier.toString(m.getModifiers());
// "public abstract"
Field f = Payable.class.getDeclaredField("CURRENCY");
Modifier.toString(f.getModifiers());
// "public static final"

So interface methods are public abstract and interface fields are public static final. Writing those keywords by hand is legal but redundant. The one thing you cannot do is narrow any of it, which is why every implementor is obliged to publish the method publicly.

A common confusion puts interfaces "before" classes in the design hierarchy. An interface is not a stripped-down class. It is a different tool with a different job, and choosing between the two is a design decision rather than a matter of preference.

2) Multiple Inheritance of Type

A class may extend exactly one class, because a class carries state and there is no defensible way to combine two copies of it. A class may implement any number of interfaces, because an interface carries only a promise, and two promises can be combined without conflict.

Main.java
Run Online
final class CardPayment implements Payable, Auditable, Serializable {
    // three contracts, one object
}

This is where the phrase "multiple inheritance" comes from, and it is worth being precise about what is inherited. Java inherits the type and the contract from several interfaces. It does not inherit state or implementation from several sources, and the diamond problem that plagues C++ simply does not arise for that reason.

Interfaces may also extend other interfaces, which lets you build up a hierarchy of promises:

Main.java
Run Online
interface Closeable2 extends AutoCloseable {
} // AutoCloseable has one abstract method

3) Default Methods and Why They Exist

Before Java 8 every interface method had to be abstract, which created a genuine versioning trap. Adding a method to an interface meant every existing implementor had to be found and updated, and any one missed was a compile error.

Main.java
Run Online
interface PayableV1 {
    long amountOf();
}// v2 adds a new ABSTRACT method. ModernPayment now fails to compile:
interface PayableV2 extends PayableV1 {
    String currency();
}// error: ModernPayment is not abstract and does not override
//        abstract method currency() in PayableV2

A default method removes that trap, because it arrives with an implementation:

Main.java
Run Online
interface PayableV2 extends PayableV1 {
    default String currency() {
        return "UNKNOWN";
    }
}

Now ModernPayment compiles untouched. Implementors that care override the method; implementors that do not inherit a sensible fallback. This is not a theoretical concern. Iterable.forEach, Collection.removeIf, List.sort, and Comparator.reversed are all default methods added to interfaces that already had thousands of implementors, and every one of them compiled without a single downstream change.

Overriding is genuinely optional, which is the point:

Main.java
Run Online
interface Auditable {
    long amountOf();
    default String auditTrail() {
        return "amount " + amountOf();
    }
}final class CardPayment implements Auditable {
    public long amountOf() {
        return 1200;
    } // auditTrail() is inherited unchanged
}

4) How the Compiler Resolves a Default Method


Three rules the compiler applies in order to resolve a default method: the class wins, the most specific interface wins, and unrelated interfaces are a compile error broken with an override or a qualified super call
Which default method wins when more than one could apply.

Once a default method exists, a class can inherit several candidates for the same signature, and javac resolves that with three rules applied in order.

Rule 1: the class wins. A method written on the implementing class always overrides an interface default. No conflict is reported, because there is nothing ambiguous about it.

Main.java
Run Online
interface A {
    default void go() {
        System.out.println("A");
    }
}class C implements A {
    @Override public void go() {
        System.out.println("class wins");
    }
}// prints "class wins"

Rule 2: the most specific interface wins. When one interface extends another and both declare the method, the subinterface is more specific and its version is used. Still no error.

Main.java
Run Online
interface A2 {
    default void go() {
        System.out.println("A");
    }
}interface B2 extends A2 {
    default void go() {
        System.out.println("B, more specific");
    }
}class C2 implements B2 {
}// prints "B, more specific", and C2 needs no method of its own

Rule 3: unrelated interfaces are a conflict. This is the case people actually hit. When two interfaces that do not extend each other both declare the same default, there is no principled winner, so the compiler refuses to choose.

Main.java
Run Online
interface A3 {
    default void go() {
        System.out.println("A");
    }
}interface B3 {
    default void go() {
        System.out.println("B");
    }
}class Both implements A3, B3 {
}// error: types A3 and B3 are incompatible;
//        class Both inherits unrelated defaults for go() from types A3 and B3

There are exactly two ways out, and both put the decision back in your hands.

Main.java
Run Online
class Decides implements A3, B3 {
    @Override public void go() {
        // option 1: decide for yourself
        System.out.println("mine");
    }
}class Delegates implements A3, B3 {
    @Override public void go() {
        // option 2: delegate to one parent
        A3.super.go();
    }
}

One restriction catches people: a qualified super call works only on a direct parent interface. If B extends A, a class implementing only B cannot write A.super.go(), and gets "not an enclosing class" instead.

5) Static and Private Methods in an Interface

Java 8 added static methods to an interface. These are utility methods that belong to the interface's own namespace and are never inherited, so they cannot be called through an implementing class or a reference.

Main.java
Run Online
interface Payables {
    static Payable of(long amount) {
        return new CardPayment(amount, false);
    }
}long AMOUNT = 500;
Payable p = Payables.of(AMOUNT);
// correct
Payable q = p.of(AMOUNT);
// compile error, not inherited

Java 9 added private methods, which solve a problem defaults created: two default methods often need to share a helper, and without private that helper would have to be public and become part of the interface's contract.

Main.java
Run Online
interface Auditable2 {
    private static String normalise(long v) {
        return v 

normalise and stamp are implementation detail. Nobody outside the interface can call them, which is what keeps the public surface small as the interface grows.

6) Functional Interfaces and Lambdas

An interface with exactly one abstract method is a functional interface, whatever else it contains. The @FunctionalInterface annotation is optional but worth adding, because the compiler then verifies the count for you.

Main.java
Run Online
@FunctionalInterfaceinterface Transformer {
    String apply(String input);
    default Transformer twice() {
        // defaults do not count
        return s -> apply(apply(s));
    }
}

Since defaults and statics are excluded from the count, a functional interface may have several of them and still take a lambda:

Main.java
Run Online
Transformer t = s -> s + "-";
System.out.println(t.apply("ada"));
// ada-
System.out.println(t.twice().apply("ada"));
// ada--

The default method composes itself, so twice() returns a new Transformer that applies the original twice. Notice the return type: a default method may return the functional interface itself, which is how small reusable combinators are built without a single named class.

This is the mechanism behind the standard library's functional types such as Runnable, Callable, Comparator, and Function, all of which are single-abstract-method interfaces. A default method that throws AbstractMethodError at run time can break the rule at source level, which is precisely why the annotation exists.

7) Interface or Abstract Class

PointInterfaceAbstract class
Per-object stateNoneYes, any modifier
ConstructorsNot allowedAllowed and used via super
Parents per typeAny number of interfacesExactly one class
Method bodiesdefault, static, and private since Java 8 and 9Any mix, including shared constructor logic
Can be instantiatedNoNo
Best suited toDeclaring a capability or roleSharing an implementation and a contract

Reach for an interface when you are naming what a thing can do and the implementations are genuinely unrelated. Reach for an abstract class when the subtypes share data or a workflow that must be written once.

They are not competitors and both can be used in one hierarchy. An abstract class can implement an interface and leave the methods unimplemented, which is often the cleanest shape when a family shares a base implementation but should also advertise a role.

8) Common Misconceptions

ClaimVerdict
Interface methods need the public abstract keywordsTrue but redundant. They are implied.
An interface field can be non-final or per-objectFalse. Always public static final.
Adding a method to an interface breaks every implementorFalse since Java 8. A default method does not.
Interfaces give full multiple inheritancePartly. The type is inherited, not state.
Two defaults with the same name are always an errorFalse. Only for unrelated interfaces.
Interface static methods are inheritedFalse. They must be called on the interface.
A functional interface can have only one method totalFalse. Only one abstract method.
Interfaces are slower than abstract classes at run timeFalse. There is no such cost.

9) When to Use One

Interfaces earn their keep when you want to name a capability that unrelated types share. Comparable, AutoCloseable, Serializable, Runnable, and Iterator are all standard-library examples, and each one lets code accept anything that satisfies the contract without knowing the concrete type.

That is the practical test: if your method parameter only ever calls methods declared on the interface, type the parameter as the interface. It keeps callers decoupled and makes the method testable with a small hand-written implementation.

Prefer an abstract class when you have noticed the same fields or the same sequence of calls appearing in three or more subclasses. At that point the duplication is real, and an abstract class moves it somewhere the compiler enforces.

Do not add a default method merely because you can. Every default method is permanent API on the interface, and it must keep working for every present and future implementor, including ones written by other teams.

Frequently Asked Questions

What is the difference between an interface and an abstract class in Java?


An interface carries no per-object state and declares no constructor, so it can describe a capability but not an implementation. An abstract class holds fields, runs constructors, and can mix abstract and concrete methods. A class may implement any number of interfaces but extend only one class, which is why interfaces provide multiple inheritance of type without the diamond problem.

Can an interface have instance fields?


No. Every field in an interface is implicitly public static final, so it belongs to the interface rather than to any object and cannot vary per instance. Reflection confirms the modifiers are stored exactly that way. To hold per-object state you need a class, which is the main reason interfaces cannot replace abstract classes.

Why do interface methods not need the abstract keyword?


Because it is implied. An interface method declared with a body is a default method, and one with a static body is a static method, so anything left over is implicitly public abstract. Writing the keywords out is legal and does nothing.

How does Java resolve two default methods with the same name?


Three rules, in order: a method on the implementing class wins; failing that, the most specific interface wins, so a subinterface beats its parent; failing that, if two unrelated interfaces both declare it, the compiler reports an error saying the class inherits unrelated defaults. You then break the tie with an override or a qualified super call such as A.super.go().

Why do default methods exist?


To let an interface gain a method without breaking existing implementors. Adding an abstract method forces every implementation in the world to add the method or fail to compile. Adding a default method brings an implementation with it, so existing code keeps working and only the implementors that want different behaviour override it. This is how Iterable.forEach and Collection.removeIf were added to the JDK.

Can a default method be overridden?


Yes, and it is optional. A class may override a default method exactly as it would override any inherited method, using the same signature rules. When it does not, it simply inherits the interface implementation. Marking the method @Override documents the intent and catches a signature typo.

What is a functional interface?


An interface with exactly one abstract method. Default and static methods do not count towards that total, so a functional interface may contain several of them and still accept a lambda. Adding the @FunctionalInterface annotation is optional but makes the compiler enforce the rule, which is useful because a stray second abstract method is easy to add by accident.

Are interface static methods inherited by implementing classes?


No. They belong to the interface itself and must be called through the interface name, such as Payables.of(AMOUNT). Calling one through an instance or a reference typed as the interface is a compile error, which is what stops static interface methods from colliding with instance methods on the implementing type.

Can an interface extend multiple other interfaces?


Yes, using extends, and the child then inherits every contract from its parents. This is how you build a larger promise out of smaller ones without involving classes. Unlike classes, the reverse is not allowed: an interface cannot extend a class, and asking for it produces "interface expected here".

One detail catches people when chaining interfaces. If the two parents both supply the same default, the conflict appears on the child interface, before any class is involved:

Main.java
Run Online
interface P1 {
    default void go() {
    }
}interface P2 {
    default void go() {
    }
}interface P3 extends P1, P2 {
}// error: types P1 and P2 are incompatible;
//        interface P3 inherits unrelated defaults for go() from types P1 and P2

P3 must therefore override go() itself, or declare a fresh default that settles the question for its own implementors.

Runnable Code Example: Interfaces in Java

Java 17+
Main.java
Run Online
// Shows what an interface guarantees, and how Java 8 default methods and
// Java 9 private methods widened its role without breaking existing code.
import java.util.ArrayList;
import java.util.List;
// Every method below is implicitly public abstract and every field is
// implicitly public static final. The modifiers are simply never written.
interface Payable {
    int CURRENCY = 840;
    // implicitly public static final
    long amountOf();
    // implicitly public abstract
    String currency();
    // implicitly public abstract
    void pay(long amount);
    // implicitly public abstract
}// A default method ships a working implementation, so an interface can grow
// a new method later without every existing implementor being recompiled.
interface Auditable {
    long amountOf();
    // implicitly public abstract
    String currency();
    // implicitly public abstract
    default String auditTrail() {
        return currency() + " " + amountOf();
    } // Java 9 added private methods, so helper logic can stay out of the
    // interface's public surface entirely.
    private static String normalise(long amount) {
        return amount <= 0 ? "0.00" : Long.toString(amount);
    } default String receipt() {
        return "receipt[" + normalise(amountOf()) + "]";
    }
}final class CardPayment implements Payable, Auditable {
    private final long amount;
    private final boolean refunded;
    CardPayment(long amount, boolean refunded) {
        this.amount = amount;
        this.refunded = refunded;
    } @Override public void pay(long requested) {
        if (requested != amount) {
            throw new IllegalArgumentException( "expected " + amount + " but got " + requested);
        } System.out.println("card charged " + requested);
    } @Override public String currency() {
        return "BDT";
    } @Override public long amountOf() {
        return amount;
    } // Overriding the default method is optional. Leaving it out inherits the
    // interface implementation, which is the entire reason defaults exist.
    @Override public String receipt() {
        return refunded ? "receipt[refunded]" : "receipt[settled]";
    }
}public class InterfaceDemo {
    public static void main(String[] args) {
        List<Payable> batch = new ArrayList<>();
        batch.add(new CardPayment(1200, false));
        batch.add(new CardPayment(850, true));
        // One loop over the interface type. CardPayment supplies the code and
        // nothing here knows or cares which implementation it is holding.
        for (Payable p : batch) {
            System.out.println("currency constant = " + Payable.CURRENCY);
            System.out.println("reported  = " + p.currency());
            p.pay(p.amountOf());
            System.out.println("audit     = " +((Auditable) p).auditTrail());
            System.out.println("receipt   = " +((Auditable) p).receipt());
            System.out.println();
        }
    }
}// Actual output:
// currency constant = 840
// reported  = BDT
// card charged 1200
// audit     = BDT 1200
// receipt   = receipt[settled]
//
// currency constant = 840
// reported  = BDT
// card charged 850
// audit     = BDT 850
// receipt   = receipt[refunded]
//

Common Java Technical Interview Questions & Answers

Interview Prep
Q1

How does Java resolve conflicting default methods when a class implements two interfaces with the same signature?

The compiler refuses to choose and reports that the class inherits unrelated defaults for that method. The class must then break the tie itself, either by overriding the method with its own implementation or by delegating to one parent with a qualified super call such as A.super.go(). The same conflict arises when an interface extends two unrelated interfaces that both supply the default, in which case the child interface must settle it.
Q2

Why can an interface not have instance fields?

Every field in an interface is implicitly public static final, so it belongs to the interface itself rather than to any object. Reflection confirms those are the modifiers actually stored. This is the structural reason an interface cannot stand in for an abstract class, since it has nowhere to keep per-object state and cannot run a constructor.
Q3

What did default methods change about interface versioning?

They removed the breakage trap. Before Java 8, adding a method to an interface forced every implementor to be updated and any miss was a compile error. A default method arrives with an implementation, so existing implementors keep compiling and only those wanting different behaviour override it. Iterable.forEach, Collection.removeIf, and List.sort were all shipped this way.
Q4

Is overriding a default method required?

No, and that is the point of the feature. A class inherits the interface implementation when it declares nothing, and overrides when it wants something different. The same signature rules apply as for any inherited method, and @Override is worth adding so a typo becomes a compile error rather than a second unrelated method.
Q5

Why do interface methods not need the public abstract keywords?

Because the modifiers are implied. A method with a body is a default method and one with a static body is a static method, so whatever is left over is treated as public abstract. Writing the keywords out is legal and has no effect on the compiled result, which reflection confirms.
Q6

What is a functional interface and is the annotation required?

It is an interface with exactly one abstract method. Default and static methods do not count towards that total, so a functional interface can carry several of them and still accept a lambda. The @FunctionalInterface annotation is optional but makes the compiler enforce the rule, which matters because a stray second abstract method added by accident compiles silently otherwise and only fails where a lambda is expected.
Q7

Are static methods in an interface inherited by implementing classes?

No. They belong to the interface and must be invoked through the interface name, for example Payables.of(500). Calling one through an instance or through a reference typed as the interface is a compile error, which is what keeps a static interface method from colliding with an instance method of the same name on the implementing type.
Q8

Can an interface extend more than one interface, and can it extend a class?

It can extend any number of interfaces, inheriting all of their contracts. It cannot extend a class at all, and writing that produces the error interface expected here. This asymmetry is the mirror image of the class rule: one class parent, many interface parents.
Q9

How do interfaces give multiple inheritance without the diamond problem?

They inherit types and contracts, never state. A class may implement many interfaces because there is no data to combine and therefore nothing ambiguous about which copy of a field should win. The diamond trouble in C++ comes from duplicated state and overridden implementations, neither of which an interface contributes.
Q10

Is there any run-time cost to programming against an interface rather than a concrete type?

No. The call site invokes through the same virtual dispatch used for any override, so the object type is resolved at run time either way. Declaring a parameter as the interface costs nothing measurable and keeps the caller decoupled from the concrete type, which is why it is the better default.

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Keep interfaces small and name a capability, not an implementation.
Type every parameter and return as the interface so callers stay decoupled.
Do not add public or abstract modifiers to interface members, they are implied.
Remember every interface field is implicitly public static final, so it is shared.
Use a default method when adding behaviour that most implementors need.
Override a default method only when the inherited behaviour is genuinely wrong.
Resolve two competing defaults explicitly, never by hoping the compiler picks.
Add @FunctionalInterface so a stray second abstract method fails the build.
Keep helper logic in private interface methods so the public surface stays small.
Call interface static methods through the interface name, never through an instance.
Prefer several small interfaces over one wide one with unrelated methods.
Reach for an abstract class instead once three subclasses share the same fields.
Design default methods knowing they are permanent API for other teams.
Add @Override to any method that supplies an interface contract.
We value your privacy & transparency

OperateTools uses cookies and local storage to ensure basic tool functionality, preserve preferences, and analyze aggregated traffic. We never sell your personal data or index your document files. Learn more in our Privacy Policy.