Both interfaces and abstract classes are powerful tools for abstraction in Java, and both can define behavior that concrete classes must provide. That similarity often creates confusion: When should you use an interface, and when should you use an abstract class?
The answer becomes much clearer when you stop thinking about syntax and start thinking about design. An abstract class is generally useful when related classes should share state, constructors, or implementation. An interface is generally useful when you want to define a contract or capability that potentially unrelated classes can provide.
A useful mental model is: abstract class = shared foundation, while interface = capability or contract.
Basic Difference
An abstract class is declared using the abstract keyword and is commonly used as a base class.
abstract class Vehicle
{
String brand;
abstract void start();
void stop()
{
System.out.println("Vehicle stopped");
}
}
An interface is declared using the interface keyword and primarily defines a contract.
interface Printable
{
void print();
}
A class extends an abstract class but implements an interface.
class Car extends Vehicle implements Printable
{
@Override
void start()
{
System.out.println("Car started");
}
@Override
public void print()
{
System.out.println("Printing car information");
}
}
Abstract Class vs Interface: Core Comparison
| Feature | Abstract Class | Interface |
|---|---|---|
| Declaration | Uses abstract class | Uses interface |
| Class relationship | Class extends it | Class implements it |
| Multiple inheritance | A class can extend only one class | A class can implement multiple interfaces |
| Instance fields | Allowed | Not allowed as ordinary instance fields |
| Constructors | Allowed | Not allowed |
| Concrete methods | Allowed | Allowed through default, static, and private methods |
| Abstract methods | Allowed | Allowed |
| Instance state | Can maintain object state | Cannot maintain per-object instance state |
| Static members | Allowed | Static fields and methods are allowed with interface-specific rules |
| Primary purpose | Shared foundation and partial implementation | Contract or capability |
Difference in Inheritance
Java allows a class to extend only one class.
class Car extends Vehicle
{
}
You cannot write:
class Car extends Vehicle, Machine
{
// Invalid
}
However, a class can implement multiple interfaces.
class Car implements Printable, Movable, Trackable
{
}
This is one of the strongest practical differences between the two mechanisms.
Abstract Class Can Have Instance Variables
An abstract class can contain normal instance fields. This makes it suitable when subclasses need to share common state.
abstract class Employee
{
String name;
double salary;
abstract void work();
}
Every employee object can have its own name and salary.
Interfaces do not provide ordinary instance fields for object-specific state.
interface Employee
{
String name = "Employee";
}
The field declared directly in the interface is a constant: it is implicitly public, static, and final.
If the abstraction needs per-object state, an abstract class is usually the more natural choice.
Abstract Class Can Have Constructors
An abstract class can define constructors to initialize common state.
abstract class Employee
{
String name;
Employee(String name)
{
this.name = name;
}
abstract void work();
}
class Developer extends Employee
{
Developer(String name)
{
super(name);
}
@Override
void work()
{
System.out.println(name + " is writing code");
}
}
An interface cannot have a constructor because it does not represent an object that can be instantiated.
Interface Cannot Store Instance State
Suppose we want every object to maintain its own balance.
An abstract class can model this naturally:
abstract class Account
{
double balance;
Account(double balance)
{
this.balance = balance;
}
abstract void withdraw(double amount);
}
An interface cannot declare balance as a normal per-object field because interface fields are constants.
Interfaces Support Multiple Contracts
Suppose a document can be printed, shared, and archived. These are independent capabilities.
interface Printable
{
void print();
}
interface Shareable
{
void share();
}
interface Archivable
{
void archive();
}
class Report implements Printable, Shareable, Archivable
{
@Override
public void print()
{
System.out.println("Printing report");
}
@Override
public void share()
{
System.out.println("Sharing report");
}
@Override
public void archive()
{
System.out.println("Archiving report");
}
}
This design is often more flexible than trying to create a complicated abstract-class hierarchy for every possible combination of capabilities.
Abstract Class Is Better for Shared Implementation
Suppose every employee has a name and a common method for displaying basic information, while the actual work differs by employee type.
abstract class Employee
{
String name;
Employee(String name)
{
this.name = name;
}
void displayName()
{
System.out.println("Employee: " + name);
}
abstract void work();
}
class Developer extends Employee
{
Developer(String name)
{
super(name);
}
@Override
void work()
{
System.out.println("Writing software");
}
}
class Tester extends Employee
{
Tester(String name)
{
super(name);
}
@Override
void work()
{
System.out.println("Testing software");
}
}
The abstract class provides common state and common implementation while leaving specialized behavior to subclasses. This is exactly where an abstract class shines.
Interface Is Better for a Capability
Now consider printing. A report, invoice, image, and document may all be printable even though they do not necessarily belong to the same inheritance hierarchy.
interface Printable
{
void print();
}
class Invoice implements Printable
{
@Override
public void print()
{
System.out.println("Printing invoice");
}
}
class Image implements Printable
{
@Override
public void print()
{
System.out.println("Printing image");
}
}
The interface describes a capability rather than forcing these classes to share a common implementation hierarchy.
Abstract Class and Interface Can Be Used Together
These are not competing features that must always be used separately. A well-designed Java application can use both.
abstract class Vehicle
{
String brand;
Vehicle(String brand)
{
this.brand = brand;
}
abstract void start();
}
interface Trackable
{
void track();
}
class Car extends Vehicle implements Trackable
{
Car(String brand)
{
super(brand);
}
@Override
void start()
{
System.out.println(brand + " car started");
}
@Override
public void track()
{
System.out.println("Car location tracked");
}
}
Here, Vehicle provides the shared foundation and state, while Trackable adds an independent capability.
A strong design can use an abstract class for what related objects are and interfaces for what those objects can do.
Abstract Methods in Both
Both abstract classes and interfaces can declare abstract methods.
abstract class Animal
{
abstract void sound();
}
interface Flyable
{
void fly();
}
A concrete class can inherit the abstract requirement from the abstract class and implement the interface contract at the same time.
class Bird extends Animal implements Flyable
{
@Override
void sound()
{
System.out.println("Bird sound");
}
@Override
public void fly()
{
System.out.println("Bird is flying");
}
}
Concrete Methods in Both
Modern interfaces can contain implemented methods, so the old rule that “abstract classes have concrete methods but interfaces do not” is no longer accurate.
An abstract class can contain ordinary concrete methods:
abstract class Vehicle
{
void stop()
{
System.out.println("Vehicle stopped");
}
abstract void start();
}
An interface can contain default methods:
interface VehicleControl
{
default void stop()
{
System.out.println("Vehicle stopped");
}
void start();
}
The important difference is not simply whether implementation is possible. The bigger question is whether the behavior belongs to a shared class foundation or to an interface contract.
Default Methods vs Abstract Class Concrete Methods
Both can provide reusable implementation, but their inheritance models are different.
| Aspect | Abstract Class Method | Interface Default Method |
|---|---|---|
| Inherited through | Class inheritance | Interface implementation |
| Object state | Can access instance fields | Cannot access ordinary object instance fields declared by the interface |
| Multiple sources | Only one superclass | Multiple interfaces are possible |
| Purpose | Shared class implementation | Reusable behavior associated with a contract |
Which One Should You Choose?
There is no universal rule saying interfaces are always better or abstract classes are always better. The correct choice depends on the relationship you are modeling.
Use an abstract class when several closely related classes genuinely share state, constructors, implementation, or a strong base-class relationship.
Use an interface when you want to define a capability, contract, or interchangeable behavior that can be implemented by multiple classes, including classes from different inheritance hierarchies.
A Practical Decision Example
Suppose you are building an e-commerce system.
Different employee types share common employee information:
abstract class Employee
{
String name;
double salary;
Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
abstract void work();
}
This is a good use of an abstract class because the subclasses share state and a common conceptual foundation.
Now suppose an employee can approve requests:
interface Approver
{
void approve();
}
Approval is a capability. Different kinds of employees or even other application components might implement it.
class Manager extends Employee implements Approver
{
Manager(String name, double salary)
{
super(name, salary);
}
@Override
void work()
{
System.out.println("Manager manages the team");
}
@Override
public void approve()
{
System.out.println("Request approved");
}
}
The two abstractions work together naturally: the abstract class models shared employee structure, while the interface models an additional capability.
Common Beginner Mistakes
- Thinking interfaces and abstract classes are interchangeable in every design.
- Assuming interfaces cannot contain implemented methods in modern Java.
- Using an abstract class when the requirement is simply an independent capability.
- Using an interface when subclasses need shared instance state and constructor-based initialization.
- Forgetting that a class can implement multiple interfaces but can extend only one class.
- Choosing an abstraction based only on syntax rather than the relationship being modeled.
Best Practices
- Choose an abstract class when shared state and implementation are central to the relationship.
- Choose an interface when modeling a capability, contract, or interchangeable behavior.
- Keep interfaces focused on clear responsibilities.
- Use abstract classes to avoid duplicated common state and implementation among closely related subclasses.
- Do not hesitate to combine an abstract class with multiple interfaces when the domain naturally requires both shared structure and additional capabilities.
Interview Insights
Question: Which is better, an abstract class or an interface?
Answer: Neither is universally better. Use an abstract class when related classes need shared state or implementation. Use an interface when you need a contract or capability that can be implemented by multiple classes.
Question: Can a class implement multiple interfaces?
Answer: Yes. A class can implement multiple interfaces but can directly extend only one class.
Question: Can an abstract class have instance variables?
Answer: Yes. An abstract class can contain normal instance fields and can initialize them through constructors.
Question: Can an interface have concrete methods?
Answer: Yes. Modern Java interfaces can contain default, static, and private methods with implementations.
Question: Can an abstract class implement an interface?
Answer: Yes. An abstract class can implement an interface without implementing every abstract interface method, leaving some implementation responsibility to its concrete subclasses.
Quick Revision
| Use Case | Prefer Abstract Class | Prefer Interface |
|---|---|---|
| Shared instance state | Yes | No |
| Constructors required | Yes | No |
| Shared implementation | Strong fit | Default methods can provide some shared behavior |
| Multiple capabilities | Limited by single inheritance | Strong fit |
| Independent contract | Usually less suitable | Strong fit |
| Multiple implementation types | Not possible through multiple class inheritance | Possible |
| Object-specific state | Supported | Not supported as ordinary interface instance fields |
| Best mental model | Shared foundation | Capability or contract |
Final Takeaway
The difference between an interface and an abstract class is ultimately a design decision, not merely a syntax decision. Choose an abstract class when related classes need a shared foundation, common state, constructors, or reusable implementation. Choose an interface when you want to define a contract or capability that different classes can adopt independently. In real Java applications, the strongest designs often use both together—an abstract class for shared structure and interfaces for flexible, composable capabilities.
