Skip to content
Java core 3 min read

Abstraction

Abstraction is the practice of exposing what a type does while hiding how it does it. It lets callers depend on a contract rather than an implementation, so internals can change freely without breaking clients. Java expresses abstraction through two tools: abstract classes and interfaces.

Abstract Methods

An abstract method declares a signature with no body. It defines an obligation: any concrete subtype must supply an implementation.

public abstract class Notifier {
    // Abstract: behavior deferred to subclasses
    public abstract void send(String message);

    // Concrete: shared logic lives here
    public void notifyAll(java.util.List<String> messages) {
        messages.forEach(this::send);
    }
}

A class containing an abstract method must itself be declared abstract.

Abstract Classes

An abstract class cannot be instantiated directly—new Notifier() is a compile error. It exists to be extended, and it can mix abstract methods with concrete methods, fields, and constructors. This makes it ideal for sharing partial implementation across a family of related types.

public class EmailNotifier extends Notifier {
    @Override
    public void send(String message) {
        System.out.println("Email: " + message);
    }
}
Notifier n = new EmailNotifier();
n.notifyAll(java.util.List.of("Hi", "Welcome"));

Output:

Email: Hi
Email: Welcome

Note: An abstract class may have zero abstract methods. Declaring it abstract simply prevents instantiation—useful for base classes meant only to be extended.

Interfaces

An interface is a pure contract. Historically every method was implicitly public abstract; since Java 8, interfaces may also carry default and static methods with bodies. A class can implement many interfaces, making them Java’s answer to multiple inheritance of type.

public interface Auditable {
    String auditTag();                       // abstract
    default void audit() {                   // default
        System.out.println("AUDIT " + auditTag());
    }
}

Abstract Class vs Interface

Choosing between the two is a recurring design decision. The table below summarizes the trade-offs.

AspectAbstract ClassInterface
InstantiableNoNo
Multiple inheritanceOne per classMany per class
FieldsAny (incl. mutable instance state)public static final constants only
ConstructorsYesNo
Method bodiesConcrete + abstractdefault/static/private + abstract
State sharingYesNo
Best modelsAn is-a with shared stateA can-do capability

When to Use Each

  • Reach for an abstract class when subtypes share state and partial implementation, and the relationship is a strong is-a (e.g., AbstractList).
  • Reach for an interface when you are defining a capability that unrelated types can adopt, or when a type needs to fulfill several contracts at once (e.g., Comparable, Closeable).

Tip: Modern Java leans toward interfaces with default methods for flexibility, falling back to abstract classes only when shared mutable state genuinely demands it.

Best Practices

  • Expose the smallest contract that satisfies your callers—abstraction is about hiding, so reveal little.
  • Prefer interfaces for capabilities; use abstract classes when shared state or constructors are required.
  • Keep abstract methods focused; a fat abstract type is hard to implement correctly.
  • Document the contract (pre/postconditions) each abstract method must honor.
  • Do not leak implementation types into your public API; return and accept abstractions.

Interview Questions

Q: Can an abstract class have a constructor? A: Yes. It runs via super(...) when a subclass is instantiated, even though the abstract class itself cannot be instantiated directly.

Q: When would you choose an abstract class over an interface? A: When subtypes must share mutable state, fields, or a non-trivial partial implementation, and the relationship is a genuine is-a. Interfaces cannot hold instance state.

Q: Can an abstract class have no abstract methods? A: Yes. It is still abstract and cannot be instantiated; this is a common pattern for base classes that only provide shared concrete behavior.

Last updated June 1, 2026
Was this helpful?