Difference between implements vs extends in Java

What does implements mean in Java?

An interface declares capabilities (method signatures, default methods, static methods, constants). A class uses implements to promise it provides those capabilities.

public interface Cache {
    Optional<String> get(String key);
    void put(String key, String value);
    default boolean contains(String key) { return get(key).isPresent(); }
}

public class InMemoryCache implements Cache {
    private final Map<String, String> store = new ConcurrentHashMap<>();
    public Optional<String> get(String key) { return Optional.ofNullable(store.get(key)); }
    public void put(String key, String value) { store.put(key, value); }
}

Key points:

  • A class can implement multiple interfaces: class A implements I1, I2 { ... }.
  • Interfaces can have default methods (since Java 8), helping evolve APIs without breaking implementors.
  • Records and enums can implement interfaces.
  • Interfaces cannot hold state (beyond public static final constants).

What does extends mean in Java?

1) Class → Class (single inheritance)

A class can extend one other class to reuse state/behavior and specialize it.

public abstract class Shape {
    public abstract double area();
}

public class Rectangle extends Shape {
    private final double w, h;
    public Rectangle(double w, double h) { this.w = w; this.h = h; }
    @Override public double area() { return w * h; }
}

2) Interface → Interface (multiple inheritance of type)

An interface can extend one or more interfaces to combine contracts.

public interface Startable { void start(); }
public interface Stoppable { void stop(); }
public interface Lifecycle extends Startable, Stoppable { }

Notes:

  • Classes cannot extend multiple classes.
  • Use super(...) to call a superclass constructor; use @Override to refine behavior.
  • If two parent interfaces provide the same default method, the implementing class must disambiguate by overriding.

Differences at a glance

Topicimplementsextends (class→class)extends (interface→interface)
PurposePromise behavior via interfaceReuse/ specialize implementation & stateCombine contracts
Multiple inheritanceClass can implement many interfacesNot allowed (single superclass)Allowed (an interface can extend many)
StateNo instance state in interfaceInherits fields and methodsNo instance state
ConstructorsN/ASubclass calls super(...)N/A
API evolutiondefault methods helpRisky; changes can rippledefault in parents propagate
Typical usePlug-in points, ports, test seamsTrue specialization (“is-a”)Build richer capability sets

When should I use each?

Use implements (interfaces) when:

  • You want flexible contracts decoupled from implementations (e.g., PaymentGateway, Cache, Repository).
  • You need multiple behaviors without tight coupling.
  • You care about testability (mock/fake implementations in unit tests).
  • You’re designing hexagonal/clean architecture ports and adapters.

Use extends (class inheritance) when:

  • There’s a strong “is-a” relationship and shared state/behavior that truly belongs in a base class.
  • You’re refining behavior of a framework base class (e.g., HttpServlet, Thread, java.io streams).
  • You need protected hooks / template methods for controlled extension.

Avoid overusing inheritance when composition (a field that delegates) is clearer and safer.

Why do we need them? Importance & benefits

  • Abstraction & decoupling: Interfaces let you program to capabilities, not concrete types, enabling swap-in implementations.
  • Reuse & specialization: Inheritance centralizes common behavior, reducing duplication (when it’s a true fit).
  • Polymorphism: Callers depend on supertype/interface; implementations can vary behind the scenes.
  • API evolution: Interfaces with default methods allow additive changes with fewer breaking changes.
  • Testability: Interfaces create clean boundaries for mocks/stubs; inheritance can provide test doubles via small overrides.

Practical examples (real-world flavored)

Spring Boot service port with an adapter

public interface EmailSender {
    void send(String to, String subject, String body);
}

@Service
public class SmtpEmailSender implements EmailSender {
    // inject JavaMailSender, etc.
    public void send(String to, String subject, String body) { /* ... */ }
}

// Usage: depend on EmailSender in controllers/use-cases, not on SMTP details.

Specializing a framework class (carefully)

public class AuditInputStream extends FilterInputStream {
    public AuditInputStream(InputStream in) { super(in); }
    @Override public int read() throws IOException {
        int b = super.read();
        // audit logic...
        return b;
    }
}

Modern features & gotchas

  • Default methods conflict: If A and B define the same default m(), a class implements A, B must override m() to resolve the diamond.
  • Abstract classes vs interfaces:
    • Use abstract classes when you need shared state, partial implementations, or constructors.
    • Use interfaces to define capabilities and support multiple inheritance of type.
  • Sealed classes (Java 17+): Control which classes can extend a base:
    public sealed class Token permits JwtToken, ApiKeyToken { }
  • Records: Can implements interfaces, great for DTOs with behavior contracts:
    public record Money(BigDecimal amount, Currency currency) implements Comparable<Money> { ... }

Integration into your team’s software development process

1) Architecture & layering

  • Define ports as interfaces in application/core modules (e.g., PaymentProcessor, UserRepository).
  • Implement adapters in infrastructure modules (JdbcUserRepository, StripePaymentProcessor).
  • Expose services via interfaces; keep controllers/use-cases depending on interfaces only.

2) Coding standards

  • Guideline: Prefer implements + composition; justify any extends in code review.
  • Naming: Interfaces describe capability (*Service, *Repository, *Gateway); implementations are specific (Jdbc*, S3*, InMemory*).
  • Visibility: Keep base classes package-private when possible; avoid protected fields.
  • Final classes/methods: Mark classes final unless a deliberate extension point.

3) Testing

  • Unit tests mock interfaces (Mockito/Stub implementations).
  • For inheritance, favor template methods and override only documented hooks in tests.

4) Code review checklist

  • Is this a true “is-a”? If not, prefer composition.
  • Are we depending on interfaces at boundaries?
  • Could an interface with a default help evolve this API safely?
  • Are we avoiding deep inheritance chains (max depth 1–2)?

5) Tooling & enforcement

  • Add static analysis rules (e.g., Error Prone/Checkstyle/Sonar) to flag deep inheritance and unused protected members.
  • Architectural tests (ArchUnit) to enforce “controllers depend on ports, not on adapters.”

Common pitfalls & how to avoid them

  • “God” base classes: Too much logic in a superclass → fragile subclasses. Split responsibilities; use composition.
  • Leaky abstractions: Interfaces that expose implementation details limit flexibility. Keep them capability-focused.
  • Over-mocking concrete classes: Depend on interfaces at boundaries to keep tests simple and fast.
  • Default method ambiguity: If combining interfaces with overlapping defaults, override explicitly.

FAQ

Can an interface extend a class?
No. Interfaces can only extend interfaces.

Can a class both extend and implement?
Yes: class C extends Base implements I1, I2 { ... }.

Is multiple inheritance supported?
For classes: no. For interfaces: yes (an interface may extend multiple interfaces; a class may implement multiple interfaces).

Interface vs abstract class—quick rule of thumb?
Need shared state/constructors → abstract class. Need flexible capability and multiple inheritance of type → interface.

Summary

  • Reach for implements to define what something can do.
  • Use extends to refine how something does it—only when it’s truly the same kind of thing.
  • Bake these choices into your architecture, guidelines, tests, and tooling to keep designs flexible and maintainable.