ProgrammingJava Developer

Describe the key differences between abstract classes and interfaces in Java, as well as scenarios when to use each of them.

Pass interviews with Hintsage AI assistant

Answer

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"); } }

Trick Question

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.


Examples of real mistakes due to ignorance of the subtleties of the topic


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.