When should you use an abstract class rather than an interface, and what does the choice give you?
The deciding factor is whether the subclasses share state and shared implementation. Here the abstract class holds the collection, and the shared find method is written once against it. Neither of those is possible through an interface, because interfaces carry no instance state.
public class Main {
public static void main(String[] args) {
Repository r = new InMemoryRepository();
r.save("a");
r.save("b");
System.out.println(r.count());
System.out.println(r.find("a"));
}
}
abstract class Repository {
protected final java.util.List<String> store = new java.util.ArrayList<>();
abstract void save(String item);
abstract int count();
String find(String item) { return store.contains(item) ? "found" : "missing"; }
}
class InMemoryRepository extends Repository {
void save(String item) { store.add(item); }
int count() { return store.size(); }
}The output shows what that buys. The in-memory repository only has to implement save and count, and it inherits the find behaviour and the storage. The caller still programs against the abstract type, so it can be swapped for a database-backed implementation later without the caller changing.
There is a second reason to prefer an abstract class, which is visibility. Members of an abstract class can be protected or package-private, so the hierarchy can share internals without exposing them to the world. Interface members are always public, so anything you put in an interface becomes part of everyone's API.
The tie-breaker to state in an interview is this: a class can extend only one abstract class but implement any number of interfaces, so composition through interfaces scales better. Use an abstract class when the subclasses are variations of one thing that genuinely share state, and use interfaces when you are describing capabilities that unrelated classes may have.