Abstract classes can contain both abstract and concrete methods (with implementation), as well as states (data fields). A class can inherit from only one abstract class. Abstract classes are used when it is necessary to generalize some part of the logic and state for a hierarchy of descendants.
Interfaces define only method signatures (prior to Java 8); starting from Java 8, they can contain methods with default implementation and static methods, but have no state. One class can implement multiple interfaces. Use interfaces to define a set of behavior that is independent of the inheritance hierarchy.
Example:
abstract class Animal { String name; public Animal(String name) { this.name = name; } abstract void makeSound(); } interface Movable { void move(); } class Dog extends Animal implements Movable { public Dog(String name) { super(name); } void makeSound() { System.out.println("Woof!"); } public void move() { System.out.println("Runs"); } }
What is the difference between an abstract class with only abstract methods and an interface before Java 8? Can they be used interchangeably?
Answer: No, not always. An interface cannot contain state (instance fields) and supports multiple inheritance, whereas inheritance from an abstract class is single. Additionally, method signatures in an interface are always public.
Story
The project required implementing multiple interfaces with similar behavior, but related to different hierarchies of objects. The developer chose to use an abstract class, which made it impossible to use multiple inheritance. This subsequently led to significant refactoring and code duplication.
Story
In a large REST API project, an interface was created with fields (constants), assuming these would be mutable values, like in a regular class. As a result, attempts to modify these fields led to Silent Failure — the values remained unchanged, and the bug took a long time to uncover.
Story
During migration to Java 8, developers added methods with implementation to the interface, but forgot to consider that some classes also inherit similarly named methods via an abstract class. This led to method conflicts and unexpected results during inheritance resolution.