Java Interface Extends Interface: Syntax & Use Cases
java interface extends interface: Learn how a Java interface can extend another interface, combine multiple interfaces, and define default methods and constants with p...
java interface extends interface requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
In Java, an interface can extend one or more other interfaces using the extends keyword. This mechanism lets you define a new interface that inherits the abstract methods, default methods, static methods, and constants from its parent interfaces. The child interface is then a subtype of all its parents, which means any class implementing the child must provide implementations for every inherited abstract method. This is a fundamental part of building type hierarchies in Java, and it is distinct from implementing an interface directly.
The Syntax for Extending an Interface
The syntax is similar to class inheritance but uses extends and allows multiple parents:
public interface Readable { String read(); } public interface Writable { void write(String data); } public interface ReadWriteable extends Readable, Writable { // inherits read() and write() }
Here, ReadWriteable extends both Readable and Writable. A class that implements ReadWriteable must provide concrete implementations for read() and write(). You can also extend a single interface:
public interface ExtendedReadable extends Readable { String readLine(); }
The ExtendedReadable interface adds a new method while inheriting read(). Classes implementing ExtendedReadable must implement both methods.
Why Extend an Interface Instead of Implementing It?
When one interface extends another, the child interface becomes a more specialized contract. This is useful when you want to express that a particular capability is a refinement of a broader one. For example, List extends Collection, adding positional access methods. By extending, you avoid repeating method signatures and establish a clear subtype relationship that the compiler enforces.
Extending an interface is not the same as implementing it. A class implements an interface to provide behavior; an interface extends another to inherit its contract. The child interface does not provide implementations; it simply adds to the contract. This distinction matters when designing APIs: you can create a hierarchy of interfaces that represent increasing levels of capability without forcing any concrete implementation details.
Extending Multiple Interfaces
Java interfaces support multiple inheritance, meaning a single interface can extend several parent interfaces. This is a key difference from classes, which cannot extend more than one superclass. Multiple inheritance of type is safe because interfaces only declare method signatures and constants, not state. For example:
public interface Serializable { // marker } public interface Loggable { void log(String message); } public interface Persistable extends Serializable, Loggable { void save(); }
A class implementing Persistable must implement log() and save(), and it is automatically considered a Serializable and Loggable due to the subtype relationship. This allows you to compose capabilities from multiple sources without the diamond problem that arises with multiple inheritance of implementation.
Default Methods in Extended Interfaces
Since Java 8, interfaces can include default methods with a body. When an interface extends another that has a default method, the child interface can override it or leave it as is. If the child interface does not override it, the default implementation is inherited. If the child interface declares the same method signature as abstract, it forces implementing classes to provide their own implementation.
Consider:
public interface Greeter { default String greet() { return "Hello"; } } public interface FriendlyGreeter extends Greeter { @Override default String greet() { return "Hi there"; } }
Here, FriendlyGreeter overrides the default method. If a third interface extends both Greeter and FriendlyGreeter and does not override greet(), the compiler will reject it because the default method is ambiguous. You must resolve the conflict explicitly in the child interface.
Constants and Static Members in Interface Hierarchies
Interfaces can declare constants (static final fields). When an interface extends another, all constants from the parent interfaces are inherited and visible through the child interface name. This can lead to accidental name collisions if two parent interfaces declare a constant with the same name. The compiler will flag such a conflict, and you must qualify the constant using the parent interface name.
Static methods in interfaces are also inherited, but they are not part of the instance contract. A child interface can call a static method from its parent directly, but implementing classes cannot call static interface methods via an instance; they must use the interface name.
Common Mistakes and Ambiguity Resolution
One common mistake is assuming that an interface extending another automatically provides default implementations for all inherited methods. That is only true for default methods. Abstract methods remain abstract, and the implementing class must supply the bodies.
Another issue arises when an interface extends multiple parents that have methods with the same signature but different return types. Java does not allow a method to be overloaded by return type alone, so the compiler will report a conflict. You must refactor the hierarchy to avoid such clashes.
When default methods conflict, you must override the method in the child interface and explicitly choose which parent's implementation to call using the InterfaceName.super.method() syntax. For example:
public interface A { default void action() { System.out.println("A"); } } public interface B { default void action() { System.out.println("B"); } } public interface C extends A, B { @Override default void action() { A.super.action(); } }
This resolves the ambiguity and gives you explicit control over the inherited behavior.
Maintainability and Design Considerations
Interface hierarchies are a powerful tool, but they can become unwieldy if overused. Deep inheritance chains make it harder to understand which methods are actually available on a given interface. Prefer shallow hierarchies and favor composition of interfaces over deep inheritance. When you design an interface that extends another, ask whether the child truly represents a subtype of the parent. If the child only reuses a few methods, consider whether a separate interface or a default method would be simpler.
Also, be mindful of the sealed interface feature introduced in Java 17. A sealed interface restricts which interfaces or classes can implement or extend it. This can make the hierarchy more predictable and improve maintainability by limiting the set of subtypes. However, it also reduces extensibility, so use it only when you control the entire hierarchy.
Finally, remember that interfaces are contracts. Extending an interface should communicate a clear relationship between capabilities. Overly complex hierarchies can make code harder to navigate and test. Keep the hierarchy as flat as possible, and use default methods to provide common behavior without forcing every implementer to duplicate logic.