Abstraction
How abstract classes and interfaces define contracts in Java — when to use each, default methods, and how abstraction enables the SOLID principles.
Last reviewed: January 2025
🔍 What Is It?
Abstract Class
- →Declared with
abstractkeyword - →Can have abstract methods (no body) and concrete methods (with body)
- →Can have instance fields and constructors
- →Cannot be instantiated directly
- →A subclass must implement all abstract methods (or also be abstract)
Interface
- →Pure contract — defines what a class can do, not how
- →All methods are implicitly public
- →Java 8+: can have
defaultmethods (concrete) andstaticmethods - →Java 9+: can have
privatemethods (for internal use by default methods) - →Fields are implicitly public static final (constants)
- →A class can implement multiple interfaces
When to use which:
- →Abstract class: shared state + partial implementation; template method pattern; "is-a" with common behavior
- →Interface: pure contract; multiple inheritance of type; unrelated classes sharing behavior (Serializable, Comparable, Runnable)
🎯 Why Do We Need It?
Abstraction enables:
- →Loose coupling — callers depend on abstractions, not implementations
- →Testability — inject mock implementations in tests
- →Replaceability — swap implementations without changing callers
- →Parallel development — teams work against an interface contract before implementation exists
- →Framework integration — Spring, JPA, and all major frameworks work through interfaces
The Dependency Inversion Principle (SOLID) states: high-level modules should depend on abstractions. This is impossible without abstract classes and interfaces.
🏗️ What Happens in Real Projects?
In every Spring Boot project:
// Interface: the contract
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
List<User> findByDepartmentAndActive(String dept, boolean active);
}
// Spring Data generates the implementation at runtime — you never write it
// Interface: service contract
public interface PaymentService {
PaymentResult process(PaymentRequest request);
void refund(String paymentId, BigDecimal amount);
}
// Implementation (can be swapped without changing callers)
@Service
public class StripePaymentService implements PaymentService { ... }
// In tests: mock PaymentService, don't call Stripe⚙️ How It Works
Abstract Method Resolution:
When you call an abstract method, Java uses dynamic dispatch to find the concrete implementation in the actual object's class.
Interface Default Methods:
Java 8+ allows default methods in interfaces — concrete implementations that subclasses inherit. This enables adding methods to interfaces without breaking existing implementations.
Functional Interfaces:
An interface with exactly one abstract method is a functional interface. It can be implemented with a lambda expression. @FunctionalInterface annotation enforces this.
Interface Segregation Principle:
Keep interfaces small and focused. A fat interface (20 methods) forces implementors to implement methods they don't need. Split into smaller, cohesive interfaces.
💻 Example
Abstract Classes and Interfaces in a Repository Pattern — How abstraction enables testable, swappable data access in enterprise Java.
🤔 Common Confusions
❓ When should I use an abstract class instead of an interface?
Use abstract class when: (1) you have shared state (fields) that all subclasses need, (2) you want to provide partial implementation, (3) you are using the template method pattern. Use interface when: (1) unrelated classes need to share a contract, (2) you want multiple inheritance of type, (3) you are defining a pure API. In modern Java, interfaces with default methods cover most cases where abstract classes were previously used.
❓ What is the difference between an interface and an abstract class in Java 8+?
After Java 8, the gap narrowed significantly. Interfaces can now have default and static methods. The remaining differences: abstract classes can have instance fields and constructors; interfaces cannot. A class can implement multiple interfaces but extend only one abstract class. Abstract classes can have non-public methods; interface methods are always public (except private helper methods in Java 9+).
🚨 Common Production Issues
Fat interfaces — an interface with 20 methods forces implementors to implement all of them. Split into smaller, focused interfaces (Interface Segregation Principle).
Default method conflicts — if a class implements two interfaces with the same default method signature, it must override the method to resolve the conflict.
Leaky abstractions — an abstraction that forces callers to know implementation details defeats the purpose. Keep interfaces clean and implementation-neutral.
✅ Best Practices
Keep interfaces small and focused — Interface Segregation Principle.
Name interfaces as capabilities: Serializable, Comparable, Runnable (not ISerializable).
Use @FunctionalInterface for single-method interfaces to enable lambda usage.
Use abstract classes for template method pattern — define the algorithm in the abstract class.
Depend on the narrowest interface that satisfies your needs (List vs Collection vs Iterable).
🏛️ Architect's Note
In Spring Boot, the standard pattern is: define a service interface, implement it in a @Service class, inject the interface everywhere else. This enables: (1) unit testing with mocks, (2) swapping implementations (e.g., switch from Stripe to PayPal by swapping the @Primary service), (3) AOP proxies (Spring wraps your service in a proxy for @Transactional, @Cacheable, etc.). Without the interface, Spring can still proxy with CGLIB, but interface-based proxying is cleaner.
💬 Frequently Asked Questions
🎯 Key Takeaways
🔗 Related Topics
🎯 Practice this topic in interviews
Core Java Interview Prep
Practice interview questions that connect directly to this technology track.
↗ Where this topic fits
Core Java Technology Guide
Return to the Core Java learning hub.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Sources
Sources / References
Use these Core Java references to verify the concept in official docs and continue into the most relevant SplashRide pages.
Official documentation
Related SplashRide pages
SplashRide Core Java learning path
Browse the full Core Java topic collection and learning order on SplashRide.
Core Java Interview Prep
Practice Core Java interview questions and scenario-based answers.
Backend Engineer Career Path
A structured journey through Core Java, Spring Boot, production backend engineering, and interview preparation.
Full Stack Java Developer Career Path
A guided route through frontend foundations, Java backend engineering, delivery workflows, and interview readiness.
Inheritance
How Java inheritance works — extends, super, method overriding, and when to use inheritance vs composition in real enterprise projects.
Java Polymorphism: Overloading, Overriding, and Dynamic Dispatch
Learn Java polymorphism with runnable examples of overriding and overloading, declared versus runtime types, null overloads, static hiding, and interface contracts.