Interfaces vs Abstract Classes Interview Questions & Answers
Java interfaces vs abstract classes interview questions — abstraction, default and static interface methods, functional and marker interfaces, multiple inheritance of behavior, interface constants, enums and when to use each.
Abstraction is exposing a simplified contract while hiding implementation detail. In Java you achieve it with interfaces (pure contract) and abstract classes (partial implementation). Callers depend on the abstract type, not the concrete class.
interface PaymentGateway { void charge(int cents); }
class StripeGateway implements PaymentGateway {
public void charge(int cents) { /* API calls hidden here */ }
}
PaymentGateway gw = new StripeGateway(); // code depends only on the contract
The payoff is decoupling: you can swap StripeGateway for PayPalGateway
without touching the calling code — the basis of "program to an interface."
- Abstract class — can have state (fields), constructors, and a mix of concrete and abstract methods. A class extends one. Models an is-a with shared implementation.
- Interface — a contract; historically only abstract methods, now also
default/static/privatemethods, but no instance state (onlypublic static finalconstants). A class implements many.
abstract class Shape {
private String name; // state allowed
abstract double area(); // subclasses must implement
String describe() { return name + ": " + area(); }
}
interface Drawable { void draw(); default void hide() { } }
Rule of thumb: use an interface for a capability multiple unrelated classes
can have (Comparable, Runnable); use an abstract class when subclasses
share state or implementation and form a tight family.
An abstract class is declared abstract and cannot be instantiated with
new — it exists to be extended. It can mix abstract methods (no body, must be
implemented) with concrete methods and fields, providing a partial
implementation subclasses complete.
abstract class Animal {
abstract String sound(); // must override
void describe() { System.out.println("Says " + sound()); } // shared
}
// Animal a = new Animal(); // ERROR — abstract, can't instantiate
Animal a = new Dog(); // OK via a concrete subclass
A class with any abstract method must itself be abstract (but an abstract
class can have zero abstract methods). Rule of thumb: abstract class =
"shared base you're not meant to use directly."
Yes. Even though you can't new an abstract class directly, its constructor
runs when a subclass is instantiated, via the implicit/explicit super(...)
call — it initializes the abstract class's slice of the object.
abstract class Shape {
final String name;
Shape(String name) { this.name = name; } // runs during subclass construction
}
class Circle extends Shape {
Circle() { super("circle"); } // must chain to it
}
Interfaces, by contrast, cannot have constructors (no instance state to initialize). Rule of thumb: abstract classes initialize shared state through their constructor; interfaces can't.
A default method provides a body inside an interface using the default
keyword. They were added in Java 8 so interfaces could evolve — e.g. adding
forEach to Iterable — without breaking every existing implementer.
interface Greeter {
String name();
default String greet() { return "Hello, " + name(); } // optional to override
}
If a class inherits conflicting defaults from two interfaces, it must
override to resolve the ambiguity (it can call Iface.super.method()).
Interfaces can also have static and private helper methods now — but still
no instance state.
Yes (Java 8 added static, Java 9 added private):
static— utility methods called on the interface itself, not inherited by implementers (e.g.Comparator.comparing(...)).private/private static— helper methods that share code betweendefault/staticmethods without exposing it.
interface Validator {
boolean valid(String s);
static Validator notEmpty() { return s -> s != null && !s.isEmpty(); }
default boolean validAll(List<String> xs) { return xs.stream().allMatch(this::valid); }
}
Rule of thumb: static for factories/utilities tied to the type, private
to DRY up the bodies of default methods — interfaces are now mini-toolkits, not
just contracts.
Only constants. Every field in an interface is implicitly public static final, so it must be assigned at declaration and can never change — there's
no instance state.
interface Physics {
double SPEED_OF_LIGHT = 299_792_458; // implicitly public static final
}
Physics.SPEED_OF_LIGHT; // accessed via the interface
The old "constant interface" pattern (implementing an interface just to inherit
its constants) is an anti-pattern — use an enum or a final class with a
private constructor instead. Rule of thumb: interfaces hold constants and
behavior, never mutable state.
A functional interface has exactly one abstract method (SAM — Single
Abstract Method), so it can be the target type of a lambda or method
reference. The @FunctionalInterface annotation makes the compiler enforce
the "one abstract method" rule.
@FunctionalInterface
interface Transformer { String apply(String s); }
Transformer upper = s -> s.toUpperCase(); // lambda implements the SAM
upper.apply("hi"); // "HI"
default/static methods don't count against the one-abstract-method limit.
Examples: Runnable, Comparator, Function, Predicate. Rule of thumb:
one abstract method = lambda-compatible.
A marker interface has no methods — it just tags a class so that code (or
the JVM) can detect a capability at runtime via instanceof. Classic examples:
Serializable, Cloneable, RandomAccess.
class Config implements Serializable { } // "this class may be serialized"
The JVM checks if (obj instanceof Serializable) before serializing. Modern
Java often prefers annotations for metadata, but marker interfaces still
give you compile-time type checking and instanceof support that annotations
don't.
Yes. If two interfaces declare the same abstract method, one implementation
satisfies both. But if they provide conflicting default methods, the class
must override to break the tie, optionally delegating with
Interface.super.method().
interface A { default String hi() { return "A"; } }
interface B { default String hi() { return "B"; } }
class C implements A, B {
@Override public String hi() {
return A.super.hi(); // explicitly choose A's default
}
}
This is Java's controlled answer to the multiple-inheritance "diamond problem": multiple types are allowed, but conflicting behavior must be resolved explicitly.
A class can implements many interfaces, inheriting multiple type
contracts — and, since Java 8, multiple default implementations. That's
multiple inheritance of type and behavior, without multiple inheritance of
state (which is what causes the classic diamond problem).
interface Swimmer { default void move() { System.out.println("swim"); } }
interface Flyer { default void glide() { System.out.println("glide"); } }
class Duck implements Swimmer, Flyer { } // inherits both behaviors
Because interfaces hold no instance fields, there's no ambiguous state to merge. Rule of thumb: interfaces = safe multiple inheritance of capability; classes = single inheritance of implementation.
Choose by what you need to share:
- Interface — a capability that unrelated classes can have, multiple inheritance of type, or a lambda target. No shared state.
- Abstract class — a family of related classes sharing fields, a constructor, or substantial implementation.
interface Comparable<T> { int compareTo(T o); } // any class can be comparable
abstract class HttpServlet { /* shared request plumbing + state */ }
They combine well: declare the API as an interface, offer an
AbstractXxx skeletal class for implementers (like AbstractList). Rule of
thumb: default to an interface; reach for an abstract class only when you must
share state/implementation.
The class wins — "class always beats interface." A concrete method
inherited from a superclass takes priority over a default method from an
interface, even if the interface is "more specific."
class Base { public String id() { return "class"; } }
interface Tagged { default String id() { return "interface"; } }
class Item extends Base implements Tagged { }
new Item().id(); // "class" — superclass method wins over default
Among interfaces, a more-specific interface's default beats a less-specific one; ties must be resolved manually. Rule of thumb: superclass method > interface default > you must override.
An enum defines a fixed set of named instances. Unlike int constants,
enums are type-safe, can have fields, constructors, and methods, and
each constant can even override behavior.
enum Planet {
EARTH(9.81), MARS(3.71);
private final double gravity;
Planet(double g) { this.gravity = g; } // constructor
double weight(double mass) { return mass * gravity; }
}
Planet.MARS.weight(70); // type-safe, behavior attached
Enums are implicitly final singletons (one instance per constant), work in
switch, provide values()/valueOf()/ordinal(), and are the recommended
way to implement singletons.
Yes. An enum can implements an interface, and it can declare abstract
methods that each constant overrides — giving per-constant behavior (a
clean replacement for switch over the enum).
interface Op { int apply(int a, int b); }
enum Math implements Op {
ADD { public int apply(int a, int b) { return a + b; } },
MUL { public int apply(int a, int b) { return a * b; } };
}
Math.ADD.apply(2, 3); // 5 — each constant has its own body
An enum can't extends a class (it implicitly extends java.lang.Enum), but
interfaces are open to it. Rule of thumb: use constant-specific method bodies
to attach behavior to enum values instead of branching on them.
More Object-Oriented Programming interview questions
More ways to practice
The self-quiz is live. Get notified when mock interviews and new question packs drop.