Understanding the Java implements Keyword
Learn how the java implements keyword binds a class to an interface, covers multiple interfaces, default methods, and common pitfalls.
What the implements Keyword Does in Java
In Java, an interface defines a contract of abstract methods that a class must provide. The java implements keyword is used in a class declaration to state that the class agrees to fulfill that contract. When a class implements an interface, it must provide concrete implementations for all abstract methods declared in the interface, unless the class itself is abstract. The implements keyword is the mechanism that ties a class to an interface at compile time, enabling polymorphism and allowing the class to be used wherever the interface type is expected.
Consider a simple interface:
public interface Drawable { void draw(); }
A class that implements this interface must supply a draw() method:
public class Circle implements Drawable { @Override public void draw() { System.out.println("Drawing a circle"); } }
The @Override annotation is optional but recommended because it lets the compiler verify that the method actually overrides an interface method.
Declaring a Class That Implements an Interface
The syntax for implementing an interface is straightforward. The implements clause appears after the extends clause, if any, and before the class body. A class can implement multiple interfaces by separating them with commas.
public class Rectangle implements Drawable, Resizable { @Override public void draw() { // implementation } @Override public void resize(double factor) { // implementation } }
When a class implements multiple interfaces, it must implement every abstract method from all of them. If the interfaces declare methods with the same signature, the class provides a single implementation that satisfies both interfaces. This is a common source of confusion because the class does not need to distinguish which interface a method comes from; it simply provides the behavior.
Implementing Multiple Interfaces
Multiple interface implementation is a core feature of Java's type system. It allows a class to be used in multiple contexts without relying on deep inheritance hierarchies. For example, a class might implement both Comparable and Serializable to support sorting and serialization.
public class Employee implements Comparable<Employee>, Serializable { private String name; private int salary; @Override public int compareTo(Employee other) { return Integer.compare(this.salary, other.salary); } }
The class must provide compareTo and also satisfy the Serializable marker interface, which has no methods. This shows that interfaces can be purely descriptive as well as behavioral.
Default Methods and Their Effect on Implementations
Java 8 introduced default methods, which allow an interface to provide a concrete implementation that a class can inherit or override. This changes what a class must implement. If an interface declares a default method, a class that implements the interface is not required to provide its own implementation unless it needs different behavior.
public interface Greeter { default String greet(String name) { return "Hello, " + name; } } public class FriendlyGreeter implements Greeter { // No need to override greet() }
Default methods were added to evolve interfaces without breaking existing implementations. However, they also introduce the diamond problem when a class implements two interfaces that provide default methods with the same signature. In that case, the class must override the method to resolve the conflict explicitly.
public interface A { default void sayHello() { System.out.println("A"); } } public interface B { default void sayHello() { System.out.println("B"); } } public class C implements A, B { @Override public void sayHello() { A.super.sayHello(); // explicitly choose A's version } }
This is a practical detail that developers encounter when mixing interfaces from different libraries.
implements Versus extends: Choosing the Right Relationship
The implements keyword is often compared to extends, but they serve different purposes. extends is used for class inheritance, where a subclass inherits fields and methods from a superclass. implements is used for interface implementation, where a class agrees to provide specific behavior without inheriting any state.
| Aspect | extends | implements |
|---|---|---|
| Type | Class or interface | Interface only |
| Inheritance | Single class, multiple interfaces | Multiple interfaces |
| State | Inherits fields | No state inheritance |
| Method contract | Can override or inherit | Must implement abstract methods |
In practice, you use extends when you want to reuse code from a base class and implements when you want to define a contract that multiple unrelated classes can fulfill. Java does not support multiple class inheritance, but it does support multiple interface implementation, which gives you flexibility without the complexity of multiple inheritance of state.
Common Mistakes When Using implements
One frequent mistake is forgetting to implement all abstract methods. The compiler will reject the class with an error like "Class is not abstract and does not override abstract method". This error is clear but can be confusing when the interface has many methods.
Another mistake is using implements with a class instead of an interface. The implements keyword only works with interface types. If you try to implement a class, you will get a compile-time error.
A subtler issue is relying on default methods to hide missing implementations. If an interface has a default method, the class can omit it, but that may lead to unexpected behavior if the default does not match the class's intended semantics. Always override default methods when the behavior is domain-specific.
Finally, be careful with method signature mismatches. An implementation must have the exact same method signature as the interface declaration, including parameter types and return type. A common error is using a covariant return type, which is allowed, but changing parameter types is not.
Design Considerations for Interface Implementations
Using implements is a design decision that affects maintainability. When you define an interface, you are creating a contract that may be implemented by many classes. Changing that contract later can break all implementations. Default methods were introduced to mitigate this, but they are not a substitute for careful design.
Prefer small, focused interfaces over large ones. The Interface Segregation Principle suggests that clients should not be forced to depend on methods they do not use. A class that implements a large interface must provide many methods, even if some are irrelevant to its role. Splitting the interface into smaller ones makes implementations easier and reduces the risk of accidental behavior.
Another consideration is the use of marker interfaces like Serializable. These interfaces have no methods and serve only to convey metadata. They can be useful, but they also add coupling. In modern Java, annotations often serve this purpose better.
Finally, think about the runtime cost. Implementing an interface has no direct performance overhead beyond the normal method dispatch. The JVM's virtual method table handles interface calls efficiently. The real cost is in code maintenance and the complexity of understanding which implementation is used at runtime. Keep the hierarchy shallow and the contracts clear to avoid debugging surprises.