Q7 of 40 · Core Java
What is the difference between abstract class and interface in Java?
Short answer
Short answer: An abstract class can have state (fields), constructors, and concrete methods; a class can extend only one. An interface defines a contract with no state (pre-Java 8) or default/static methods (Java 8+); a class can implement many. Use abstract class for shared implementation; use interface for capability contracts.
Detail
Abstract class: a class that cannot be instantiated directly but can contain fields, constructors, and any mix of abstract (must-override) and concrete (inherited-as-is) methods. Because Java allows only single class inheritance, extending an abstract class uses up your one inheritance slot.
Interface: originally a pure contract — all methods implicitly public abstract, all fields implicitly public static final. Since Java 8, interfaces can have default methods (concrete implementations) and static methods, and since Java 9, private methods. A class can implement any number of interfaces.
Key deciding factors:
- Need shared mutable state or a constructor? → abstract class. Interfaces cannot have instance fields or constructors.
- Defining a capability that unrelated classes should share (Comparable, Runnable, Iterable)? → interface. A
Dogand aDatecan both beComparablewithout sharing a parent class. - Need to extend an existing library class? → you can't add an abstract class to its hierarchy, but you can make it implement an interface.
Diamond problem: if two interfaces provide a default method with the same signature, the implementing class must override it to resolve the conflict — Java enforces this at compile time. This is the Java answer to the classic diamond problem.
In test automation, abstract class fits a BasePage with shared Playwright/Selenium setup; interface fits Navigable, Searchable, or Assertable contracts that different page objects can implement independently.
// EXAMPLE
AbstractVsInterface.java
// Abstract class — shared state and setup
abstract class BasePage {
protected final Page page; // shared state
protected final String baseUrl;
BasePage(Page page, String baseUrl) { // constructor
this.page = page;
this.baseUrl = baseUrl;
}
void navigate(String path) { // shared concrete method
page.navigate(baseUrl + path);
}
abstract String pageTitle(); // subclass must implement
}
// Interface — capability contract (no state, no constructor)
interface Searchable {
List<String> searchResults(String query);
default boolean hasResults(String query) { // Java 8+ default method
return !searchResults(query).isEmpty();
}
}
// A page can do both: extend base class AND implement capability interfaces
class ProductsPage extends BasePage implements Searchable, Filterable {
ProductsPage(Page page, String baseUrl) { super(page, baseUrl); }
@Override public String pageTitle() { return "Products"; }
@Override
public List<String> searchResults(String query) {
// implementation
return List.of();
}
}