Abstraction
A complete guide to abstraction in Java: abstract classes, abstract and concrete methods, constructors in abstract classes, interfaces and their evolution through Java 8 and 9, functional interfaces, marker interfaces, and a clear comparison between abstract classes and interfaces.
What is Abstraction?
Abstraction is about exposing what something does while hiding how it does it. When you press a button on a TV remote, you do not need to understand the infrared signal encoding and the circuit board processing happening behind the scenes. The remote gives you a simplified interface: this button changes the channel, that button adjusts the volume. The complexity is hidden behind a clean surface.
Java provides two mechanisms for achieving abstraction: abstract classes and interfaces. Both let you define a contract, a set of methods that implementing or extending classes must provide, without dictating the implementation. Callers code against the contract rather than against a specific class, which is what makes the system flexible and extensible.
Two abstraction tools
Java uses both mechanisms, and they have different strengths. Choosing correctly between them is a design skill.
- Abstract class:A class that cannot be instantiated and may contain abstract methods (contract) alongside concrete methods (shared implementation) and fields (shared state). A class can extend only one abstract class.
- Interface:A pure contract that defines method signatures without implementation (before Java 8). A class can implement any number of interfaces. Since Java 8, interfaces can also carry default and static implementations.
Abstract Classes and the abstract Keyword
An abstract class is declared with the abstract keyword placed before the class keyword. Attempting to instantiate an abstract class directly with new is a compile error. Its purpose is to serve as a partial or skeletal implementation: it defines what must exist (abstract methods) and optionally provides what is shared (concrete methods and fields). Concrete subclasses fill in the rest.
What an abstract class may contain
Abstract classes are more capable than interfaces in what they can hold.
- Abstract methods: declared with abstract, no body, must be overridden by concrete subclasses.
- Concrete methods: fully implemented methods with a body. Subclasses inherit these and may override them.
- Instance fields: regular fields that belong to each object, unlike interface variables which are constants.
- Constructors: called via super() from subclass constructors to initialise the shared fields.
- Static members: static fields and static methods, just like a regular class.
Abstract Methods
An abstract method is a method with no body. It consists only of a signature ending in a semicolon. The abstract keyword is required. Any concrete class that extends the abstract class must provide an implementation for every abstract method it inherits, otherwise the subclass itself must also be declared abstract. This is how the compiler enforces the contract.
Abstract Methods and Concrete Subclasses
JavaA Shape abstract class with an abstract area() method implemented differently by each subclass.
Concrete Methods in Abstract Classes
The value of concrete methods in an abstract class is that they provide shared behaviour that every subclass gets for free without duplicating code. If you have ten shape subclasses, they all need a describe() method. Writing it once in the abstract parent and having all ten inherit it is exactly the kind of code reuse that abstract classes are designed for. Subclasses can still override a concrete method if they need a different implementation.
Concrete Methods in an Abstract Class
JavaA logging base class providing shared concrete behaviour while leaving the core logic abstract.
Constructor in an Abstract Class
Abstract classes can and often should have constructors, even though you cannot call them with new directly. The constructor is invoked via super() from a concrete subclass constructor, and its job is to initialise the fields that the abstract class owns. Without this, all subclasses would have to initialise those shared fields themselves, which defeats the purpose of putting them in the parent.
Constructor in an Abstract Class
JavaThe abstract parent's constructor initialises shared fields; the subclass constructor handles its own.
Interfaces and the interface Keyword
An interface is declared with the interface keyword. In its traditional form (before Java 8), an interface contained only method signatures with no implementations. Every method in an interface is implicitly public abstract, so those keywords are optional. You cannot directly instantiate an interface, but you can declare variables of an interface type and assign any object that implements that interface to them.
Interface basics
Interfaces define a contract that any implementing class must fulfil.
- Method signatures in an interface are implicitly public and abstract. Writing these modifiers explicitly does no harm but adds noise.
- An interface cannot have instance fields. The only fields allowed are constants (public static final).
- Interfaces can extend other interfaces using extends. A single interface can extend multiple interfaces.
- A class implements an interface using the implements keyword. All abstract methods must be provided, or the class itself must be abstract.
Defining and Implementing an Interface
JavaA Printable interface implemented by two unrelated classes, showing how interfaces decouple types.
Implementing Multiple Interfaces
A class can implement any number of interfaces simultaneously. This is the primary way Java achieves multiple inheritance of type without the diamond problem. Each interface in the list is separated by a comma after the implements keyword. The class must provide concrete implementations for all abstract methods from all listed interfaces.
Multiple Interface Implementation
JavaA SmartDevice class that satisfies three separate interface contracts simultaneously.
Interface Variables (public static final)
Any field you declare in an interface is automatically public static final, regardless of whether you write those keywords. This means interface fields are constants shared across the entire program: they cannot be changed, they belong to the interface itself (not to any object), and they are accessible from anywhere. They must be initialised in the declaration because they are final.
Interface Variables as Constants
JavaUsing interface constants to define shared configuration values accessible to all implementors.
Default Methods in Interfaces (Java 8+)
Before Java 8, adding a new method to a published interface was a breaking change: every existing class implementing that interface would fail to compile until it provided an implementation. Java 8 introduced default methods to solve this. A default method has a body and is marked with the default keyword. Implementing classes inherit it automatically and can leave it as-is or override it if they need different behaviour.
Default method rules
Default methods integrate cleanly into the class hierarchy but come with one important conflict rule.
- A class that implements the interface inherits the default method without writing anything. This is the main use case: backward-compatible API evolution.
- A class can override a default method exactly as it would override any inherited method, simply by providing its own implementation.
- If two interfaces both declare a default method with the same signature and a class implements both, the class must override that method to resolve the ambiguity, or the compiler produces an error.
- A class's own method always takes precedence over a default method with the same signature.
Default Methods (Java 8+)
JavaAdding a new default method to an existing interface without breaking current implementors.
Static Methods in Interfaces (Java 8+)
Java 8 also added static methods to interfaces. These are fully-implemented methods that belong to the interface itself, not to any implementing class or instance. They are called using the interface name directly. Unlike default methods, static interface methods are not inherited by implementing classes and cannot be overridden. They work as utility or factory methods logically grouped with the interface they serve.
Static Methods in an Interface (Java 8+)
JavaValidator interface with static utility methods that provide ready-to-use validation logic.
Private Methods in Interfaces (Java 9+)
As default and static interface methods grew more complex, code duplication between them became a problem. Java 9 added private methods to interfaces specifically to address this. A private interface method can only be called from within the interface itself, typically as a shared helper for default and static methods. It is not inherited by implementing classes and not accessible from outside the interface.
Private Methods in an Interface (Java 9+)
JavaExtracting shared formatting logic into a private helper to avoid duplicating it across default methods.
Functional Interfaces
A functional interface is an interface that declares exactly one abstract method. This single-method contract is what makes it compatible with lambda expressions and method references introduced in Java 8. When you pass a lambda expression where a functional interface is expected, Java creates an anonymous implementation of that interface on the fly. The @FunctionalInterface annotation is optional but strongly recommended: it instructs the compiler to verify that the interface has exactly one abstract method and produces an error if it does not.
Built-in functional interfaces in java.util.function
Java 8 ships with ready-made functional interfaces for the most common patterns. You rarely need to define your own.
- Predicate<T>:boolean test(T t), tests a condition. Used in filter().
- Function<T, R>:R apply(T t), transforms an input to an output. Used in map().
- Consumer<T>:void accept(T t), consumes a value with no return. Used in forEach().
- Supplier<T>:T get(), produces a value with no input. Used for lazy initialisation.
- UnaryOperator<T>:T apply(T t), a Function where input and output are the same type.
- BiFunction<T, U, R>:R apply(T t, U u), a Function with two inputs.
Functional Interfaces and Lambda Expressions
JavaDefining a custom functional interface and using built-in ones from java.util.function.
Marker Interfaces (Serializable, Cloneable)
A marker interface is an interface with no methods and no fields whatsoever. Its sole purpose is to tag a class as having a particular property. The JVM or a framework then checks for the presence of that tag using instanceof or reflection and changes its behaviour accordingly. The marker carries meaning even though it carries no code.
The two most important marker interfaces in Java
Both are in the java.io package and have been part of Java since version 1.1.
- java.io.Serializable:Marks a class as safe to convert to a byte stream (serialise) and reconstruct from one (deserialise). ObjectOutputStream checks for this marker before serialising. If a class is not Serializable, attempting to serialise it throws NotSerializableException.
- java.lang.Cloneable:Marks a class as permitting Object.clone() to be called on it. Without this marker, clone() throws CloneNotSupportedException. The class must also override clone() and make it public to be genuinely useful.
Marker Interfaces
JavaDemonstrating Serializable and Cloneable, and defining a custom marker interface.
Abstract Class vs. Interface
This is one of the most common design questions in Java. The two mechanisms overlap significantly since Java 8, but they still serve different purposes and the choice between them reflects the nature of the relationship you are modelling.
When to use an Abstract Class
Choose an abstract class when the relationship is genuinely one of shared identity and partial implementation.
- The subclasses share common state (instance fields) that the parent should own and initialise.
- You want to provide a partial implementation with some concrete methods and leave others abstract.
- The relationship is a strong IS-A: a Dog truly is an Animal; it shares the Animal's identity, not just its interface.
- You need a constructor to enforce a valid initial state for all subclasses.
When to use an Interface
Choose an interface when you are defining a capability or a contract independent of class hierarchy.
- The capability is orthogonal to the class hierarchy: both a Document and a Spreadsheet can be Printable, but they are not the same kind of thing.
- You need multiple inheritance of type: a class needs to satisfy more than one contract.
- You are designing a public API and want maximum flexibility for implementors, who are free to extend any class they choose.
- You want to write code that works with the behaviour regardless of the specific class providing it.
Abstract Class vs. Interface: Side by Side
JavaContrasting the two mechanisms with a concrete design scenario.
Quick comparison table
A summary of the key differences between abstract classes and interfaces.
- Instantiation:Neither can be instantiated directly.
- Fields:Abstract class: any kind of field. Interface: only public static final constants.
- Constructors:Abstract class: yes. Interface: no.
- Method types:Abstract class: abstract, concrete, static. Interface: abstract, default, static, private (Java 9+).
- Inheritance/implementation:A class can extend only one abstract class. A class can implement any number of interfaces.
- Relationship modelled:Abstract class: IS-A (shared identity). Interface: CAN-DO (capability contract).
Quiz - Test Your Knowledge
Ten questions covering abstract classes, abstract methods, interface basics, multiple implementation, interface variables, default and static interface methods, private interface methods, functional interfaces, marker interfaces, and the abstract class vs. interface comparison. Read each option carefully before selecting your answer.
Knowledge Check
1. Which of the following is true about abstract classes in Java?
2. What happens if a concrete subclass does not implement all abstract methods of its parent abstract class?
3. Which statement about interface variables is correct?
4. What is the purpose of a default method in an interface (Java 8+)?
5. How many interfaces can a single class implement in Java?
6. What is a functional interface?
7. What distinguishes a marker interface from a regular interface?
8. When should you choose an abstract class over an interface?
9. Can an abstract class have a constructor?
10. What is the access level of private methods defined inside an interface (Java 9+)?