The difference between an interface and abstract class in Java is that an abstract class is a partly built class with fields, constructors and shared code that a subclass extends, whereas an interface is a contract of methods without instance state that any class can implement, and a class can implement many interfaces but extend only one class.
We use an abstract class to share code and state among closely related classes, and an interface to describe a capability that unrelated classes can offer, such as Comparable or Runnable. In practice, the two work best together.
The following example defines a storage contract as an interface and puts the shared code in an abstract class.
interface Storage { // the contract
void put(String key, String value);
String get(String key);
}
abstract class BaseStorage implements Storage { // a partial implementation
protected final Map<String, String> data = new HashMap<>(); // instance state
private final String name;
protected BaseStorage(String name) { this.name = name; } // constructor
public String get(String key) { return data.get(key); } // shared code
public String name() { return name; }
}
class MemoryStorage extends BaseStorage {
MemoryStorage() { super("memory"); }
public void put(String key, String value) { data.put(key, value); }
}
The interface names the operations and nothing more, while the abstract class already holds a map, a constructor and a working get() method. Each type gets its own section first, followed by a side-by-side comparison, the way the JDK combines the two, and a checklist for choosing one.
1. Abstract Classes Hold State and Shared Code
A class declared with the abstract keyword cannot be instantiated, and it may contain abstract methods without a body. Every other feature of a normal class stays available, such as instance fields, constructors, protected and private members, and final methods. If a class has at least one abstract method, the compiler requires the class to be abstract.
A concrete subclass extends the abstract class and implements the missing methods. The constructor of the abstract class runs as part of every subclass constructor, so the shared fields are set up in one place.
BaseStorage prefs = new MemoryStorage();
prefs.put("theme", "dark");
String theme = prefs.get("theme"); // "dark"
String storageName = prefs.name(); // "memory"
Creating a BaseStorage with new is a compile error, because the class is abstract and still has no body for put(). An anonymous subclass that fills in the gap is allowed, which is handy for a one-off variant such as a read-only store in a test.
// does not compile: BaseStorage is abstract; cannot be instantiated
BaseStorage broken = new BaseStorage("broken");
BaseStorage readOnly = new BaseStorage("read-only") {
public void put(String key, String value) {
throw new UnsupportedOperationException("read-only storage");
}
};
String readOnlyName = readOnly.name(); // "read-only"
2. Interfaces Define a Contract
An interface declares what a type can do without saying how. Its abstract methods are implicitly public and abstract, and its fields are implicitly public static final constants, so an interface cannot hold per-object state and has no constructor.
Interfaces gained method bodies in two steps. Java 8 added default and static methods, and Java 9 added private methods (JEP 213) so that default methods can share helper code. The following example uses every kind of interface member.
interface Expiring {
long MAX_TTL = 86_400; // constant, public static final
long ttlSeconds(); // abstract method
default boolean isShortLived() { // Java 8, default method
return ttlSeconds() < minutes(5);
}
static Expiring of(long seconds) { // Java 8, static method
return () -> Math.min(seconds, MAX_TTL);
}
private long minutes(long count) { // Java 9, private method
return count * 60;
}
}
Expiring session = Expiring.of(120);
boolean shortLived = session.isShortLived(); // true
long capped = Expiring.of(999_999).ttlSeconds(); // 86400
Because Expiring has a single abstract method, a lambda can implement it, which is what of() returns. A class can implement Storage, Expiring and any other interface at the same time, which gives Java multiple inheritance of type without the problems of multiple inheritance of state.
3. Interface vs Abstract Class Comparison
Default methods let interfaces carry behavior, but they still cannot carry instance state, constructors or non-public abstract methods, and that gap decides most design choices. The diagram groups what each type can contain.

The table lists the rules for Java 25, with the version that introduced each interface feature.
| Feature | Interface | Abstract class |
|---|---|---|
| Keyword for the subtype | implements (a class), extends (an interface) | extends |
| How many per class | Any number | One |
| Instance fields | No, only public static final constants | Yes, any modifier |
| Constructors | No | Yes, called through super(…) |
| Abstract methods | Implicitly public abstract | Any access except private |
| Methods with a body | default and static (Java 8), private (Java 9) | Any kind |
| final methods | No | Yes |
| protected members | No | Yes |
| Lambda implementation | Yes, if it has one abstract method | No |
| Typical JDK example | Comparable, Runnable, List | AbstractList, InputStream, Number |
Since Java 17, both can be sealed, so the author controls which subtypes may exist. Neither type can be instantiated with new, and both can declare a static main() method, so that is not a difference between them.
4. An Abstract Class That Implements an Interface
An abstract class can implement an interface without providing all of its methods, because the class itself stays incomplete. The first concrete subclass must supply whatever is still missing. In the intro, BaseStorage implements get() and leaves put() to MemoryStorage.
The JDK uses this combination on purpose. The List interface declares 25 abstract methods, and AbstractList implements almost all of them on top of get() and size(). The Javadoc calls such a class a skeletal implementation, and it turns a full List into a two-method job.
class Weekdays extends AbstractList<String> {
private final String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri"};
@Override
public String get(int index) { return days[index]; }
@Override
public int size() { return days.length; }
}
List<String> weekdays = new Weekdays();
boolean hasWed = weekdays.contains("Wed"); // true
int thu = weekdays.indexOf("Thu"); // 3
List<String> middle = weekdays.subList(1, 3); // [Tue, Wed]
boolean added = weekdays.add("Sat"); // UnsupportedOperationException
Callers see only the List interface, and Weekdays reuses the iteration, search and sublist code of AbstractList. The inherited add() throws UnsupportedOperationException until a subclass overrides it, which is the documented way to build an unmodifiable list.
5. When to Use an Interface or an Abstract Class
The question to ask is whether the types share an implementation or only a role. Classes that share fields and code belong under one abstract class, whereas classes that only promise the same operations should implement a common interface. The Oracle Java tutorial gives similar guidance, and three situations cover most cases.
- Pick an abstract class when several closely related classes share fields or code, when we need constructors to set up shared state, or when some members must stay protected or final.
- Pick an interface when unrelated classes should offer the same operation, when a class needs more than one supertype, or when callers should depend on a contract that tests can replace with a fake or a lambda.
- Pick both when a public contract has many implementations with common code. Declare the interface for callers and an abstract base class for implementers, as List and AbstractList do.
Say a web app keeps user settings in memory during tests and in Redis in production. The settings service depends on the Storage interface, and both implementations extend BaseStorage to reuse the key handling. Swapping the store becomes a one-line change where the service is created.
class SettingsService {
private final Storage storage;
SettingsService(Storage storage) { this.storage = storage; }
String theme() {
String value = storage.get("theme");
return value != null ? value : "light";
}
}
SettingsService settings = new SettingsService(new MemoryStorage());
String defaultTheme = settings.theme(); // "light"
Frameworks follow the same split. The Jakarta Servlet API ships HttpServlet as an abstract class, so each servlet inherits the request dispatching code and overrides only doGet() or doPost(), while Spring defines most extension points, such as Converter, as interfaces. The comparison also maps to two OOP concepts, namely abstraction and inheritance, and extends vs implements covers the keywords in detail.
6. Interface and Abstract Class FAQs
Constructors cause the most confusion, because one of the two types can declare them and the other cannot, and default methods come right after.
6.1. Can abstract classes have constructors in Java?
Yes. The constructor runs when a subclass is created, through the implicit or explicit super(…) call, and it typically initializes shared fields. Declaring it protected makes the intent clear.
6.2. Can an interface have a constructor?
No. An interface has no instance fields to initialize, so the compiler rejects a constructor declaration in an interface.
6.3. Can an abstract class have no abstract methods?
Yes. A class can be abstract only to prevent direct instantiation, for example a base class whose subclasses add the meaningful behavior. HttpServlet is abstract even though none of its methods is abstract.
6.4. Can an interface extend an abstract class?
No. An interface can extend only other interfaces. An abstract class, on the other hand, can implement any number of interfaces.
6.5. Did default methods make abstract classes unnecessary?
No. Default methods let an interface grow without breaking existing implementations, but an interface still cannot hold instance fields, constructors or protected methods. When implementations share state, an abstract class is still the right tool.
7. Conclusion
An abstract class is a partial implementation with state, constructors and any kind of method, and a class extends only one of them. An interface is a contract without instance state, it may contain default, static and private methods, and a class can implement many interfaces.
Choose an abstract class for shared code among close relatives and an interface for roles that unrelated classes play. For a public API with several implementations, we declare the interface for callers and add an abstract base class for implementers.
8. References
- JLS 25, abstract Classes
- JLS 25, Interface Method Declarations
- JEP 213, Milling Project Coin (private interface methods)
- Oracle Java Tutorial, Abstract Methods and Classes
- AbstractList Javadoc
Happy Learning !!
Abstract classes can hold instance variables, while interfaces cannot.
Abstract classes can have a constructor because the constructor does not define a method signature that must be matched inherited by child classes. It’s the only method that doesn’t require that same signature on child implementations