Abstraction: Abstract Classes and Interfaces โ Revision Notes
Abstraction is an OOP pillar and the source of a hugely common interview question: "abstract class vs interface โ when do you use each?". Getting the distinction right (especially in Java) is a strong signal.
What abstraction is
Abstraction means exposing only essential features and hiding implementation complexity โ the "what", not the "how". A driver uses a steering wheel without knowing the mechanism. In code, you program to an abstract type and let concrete classes fill in details.
Abstract class vs interface
An abstract class can have both abstract methods (no body) and concrete methods + state (fields); a class can extend only one. An interface is a pure contract of method signatures (Java 8+ allows default/static methods); a class can implement many.
| Abstract class | Interface | |
|---|---|---|
| Instantiable | No | No |
| State (fields) | Yes | Constants only |
| Multiple inheritance | No (single) | Yes (many) |
| Use | shared base + partial impl | capability/contract |
Exam Tricks & Tips
- ๐ฏ Use an interface for a capability/contract many unrelated classes can implement; use an abstract class to share common state + partial implementation among related classes.
- ๐ฏ A class can implement many interfaces but extend only one (abstract) class โ Java's answer to multiple inheritance.
- ๐ฏ Neither an abstract class nor an interface can be instantiated directly.
- ๐ฏ Since Java 8 interfaces can have
defaultmethods (bodies) โ the old "interfaces have no implementation" rule is outdated. - ๐ฏ Abstraction hides complexity (design level); encapsulation hides data (implementation level) โ a favourite compare-and-contrast.
- ๐ฏ "is-a with shared code" โ abstract class; "can-do / behaves-like" โ interface.
- โ Common mistake: saying a class can extend multiple abstract classes โ it can implement multiple interfaces but extend only one class.
Expected pattern
"Abstract class vs interface", "when to choose each?", "can you instantiate an abstract class?", "abstraction vs encapsulation", and "can Java classes extend multiple classes?".
Quick recap
Abstraction exposes essentials, hides complexity. Abstract class: single inheritance, can hold state + partial implementation. Interface: multiple implementation, a contract (default methods since Java 8). Neither is instantiable. Interface = capability; abstract class = shared base.
Abstraction: Abstract Classes and Interfaces โ Flashcards
Cover the answer, recall, then check. 12 cards on abstraction, abstract classes and interfaces.
Q1. What is abstraction in OOP?
A1. Exposing only essential features while hiding implementation complexity โ focusing on "what" an object does, not "how".
Q2. Can you instantiate an abstract class or interface?
A2. No โ neither can be instantiated directly; you instantiate a concrete subclass/implementer.
Q3. Key difference in inheritance between abstract classes and interfaces?
A3. A class extends only one abstract class but can implement many interfaces.
Q4. Can an abstract class have concrete methods and fields?
A4. Yes โ it can mix abstract methods with concrete methods and hold instance state (fields).
Q5. Can an interface hold state?
A5. Only constants (public static final); it defines a contract, not instance fields.
Q6. When should you prefer an interface over an abstract class?
A6. For a capability/contract that many unrelated classes can share, or when a class needs multiple such contracts.
Q7. When should you prefer an abstract class?
A7. When related classes share common state and partial implementation you want to reuse via a base class.
Q8. What did Java 8 add to interfaces?
A8. default and static methods with bodies, so interfaces can now provide some implementation.
Q9. How does abstraction differ from encapsulation?
A9. Abstraction hides complexity (design "what"); encapsulation hides and bundles data (implementation "how").
Q10. How does an interface simulate multiple inheritance in Java?
A10. A class can implement multiple interfaces, inheriting multiple contracts (and default methods) without multiple class inheritance.
Q11. What is an abstract method?
A11. A method declared without a body; subclasses must provide the implementation (or be abstract themselves).
Q12. "is-a with shared code" vs "can-do" โ which maps to which?
A12. "is-a with shared code" โ abstract class; "can-do / behaves-like" โ interface.
Abstraction: Abstract Classes and Interfaces
Abstraction is "show what, hide how". In code it takes two forms โ abstract classes and interfaces โ and choosing between them is one of the most practical OOP design decisions, so interviewers ask about it constantly.
Core idea: abstraction exposes essential behaviour while hiding implementation detail. An abstract class is a partially-implemented base you extend (an "is-a" template with shared code); an interface is a pure contract of method signatures a class promises to fulfil ("can-do" capability).
How it works
Beginner โ the two tools
abstract class Shape { // abstract class: some shared code
String name;
abstract double area(); // no body: subclasses MUST implement
void describe() { System.out.println(name + " area=" + area()); } // shared
}
interface Drawable { // interface: pure contract
void draw();
}
You cannot instantiate either directly. An abstract class can hold fields and concrete methods; a (classic) interface only declares behaviour.
Intermediate โ the key differences
| Aspect | Abstract class | Interface |
|---|---|---|
| Instantiable | No | No |
| Method bodies | Yes (mix of abstract + concrete) | Signatures (Java 8+ allows default) |
| Fields/state | Yes (instance fields) | Constants only |
| Inheritance | Single (one base) | Multiple (implement many) |
| Models | "is-a" with shared code | "can-do" capability |
Why both exist: a class can extend only one abstract class but implement many interfaces โ so interfaces give a form of multiple inheritance of type without the "diamond" state problems.
Advanced โ designing to abstractions
The Dependency Inversion Principle says: depend on abstractions, not concretions. Code against an interface and you can swap implementations freely:
interface PaymentGateway { boolean charge(int cents); }
class StripeGateway implements PaymentGateway { ... }
class Checkout {
private final PaymentGateway gw; // depends on the abstraction
Checkout(PaymentGateway gw) { this.gw = gw; } // inject any implementation
}
Now Checkout works with Stripe, PayPal, or a test mock โ none of its code changes. This is the backbone of testability and plugin architectures.
Worked example โ choosing the right tool
Suppose you model animals. All animals are a kind of Animal and share eat() logic โ abstract class Animal with a concrete eat() and abstract makeSound(). But only some animals can swim or fly โ capabilities cutting across the hierarchy โ interfaces Swimmer, Flyer.
abstract class Animal { void eat(){...} abstract void makeSound(); }
interface Swimmer { void swim(); }
class Duck extends Animal implements Swimmer, Flyer { ... }
A Duck is an Animal (single base, shared code) and can swim and fly (multiple capabilities). Trying to force "swimmer" into the class hierarchy would fail because fish and ducks share swimming but not a common concrete ancestor.
Interview & exam relevance
The perennial question: "abstract class vs interface โ when do you use which?" Answer with: shared state/code and a strict "is-a" โ abstract class; a capability usable across unrelated types, or the need to implement multiple contracts โ interface. Note Java 8 default methods blurred the line but not the single-vs-multiple-inheritance rule.
Tricks & gotchas
- A class extends one abstract class but implements many interfaces.
- An abstract class can have constructors (called by subclasses) and instance state; interfaces cannot hold instance state.
- Since Java 8, interfaces can have
default/staticmethods โ useful, but they still can't store per-object fields. - Mnemonic: "Abstract class = 'is-a' + shared code; interface = 'can-do' contract."
Choosing an abstract class purely to "share a couple of methods" when the types are not truly related by "is-a". This forces an artificial single-inheritance hierarchy and blocks the class from extending anything else. If you only need shared behaviour contracts or cross-cutting capabilities, an interface (with default methods if needed) is the better tool.
- โ- Abstraction exposes essential behaviour and hides implementation.
- โ- Abstract class: partial implementation + state, single inheritance, models "is-a".
- โ- Interface: pure contract, multiple implementation, models "can-do" capability.
- โ- Neither can be instantiated directly.
- โ- Depend on abstractions (interfaces) to enable swapping, testing and plugins.
- โAbstraction hides "how" behind "what". Use an abstract class for a true "is-a" relationship with shared state/code and single inheritance; use an interface for capability contracts and multiple inheritance of type. Program against abstractions to keep code swappable and testable.
Abstraction: Abstract Classes and Interfaces โ Worked Example
Worked Example
Problem: Model shapes so that area() must be defined by each shape but describe() is shared, and separately let some shapes be "drawable" and "serializable" independently. Decide where an abstract class fits and where interfaces fit.
Solution:
Use an abstract class when subtypes share state/implementation and form a single "is-a" family; use interfaces to mix in independent capabilities (a type can implement many).
abstract class Shape { // shared identity + code
private final String name;
Shape(String name) { this.name = name; }
abstract double area(); // each shape MUST supply this
String describe() { // shared, concrete
return name + " with area " + area();
}
}
interface Drawable { void draw(); } // capability 1
interface Serializable2 { String toJson(); } // capability 2
class Circle extends Shape implements Drawable {
private final double r;
Circle(double r) { super("Circle"); this.r = r; }
double area() { return Math.PI * r * r; } // required override
public void draw() { /* render circle */ }
}
Why this split: Shape is abstract because a bare "shape" has no area โ you cannot instantiate it (new Shape() is illegal), yet it holds common state (name) and a concrete describe() that calls the still-abstract area(). Each subclass is forced to implement area(); calling describe() dispatches to the subclass's area() (polymorphism).
Drawable and Serializable2 are orthogonal capabilities. A class can implement several interfaces but extend only one class (Java single inheritance), so capabilities that cut across unrelated types belong in interfaces, not the base class. Circle chooses to be Drawable but need not be serializable.
Answer: Put shared state and template behaviour (describe) in an abstract Shape with an abstract area() each shape must implement; express cross-cutting, independently-chosen abilities (Drawable, Serializable2) as interfaces a type can mix in. You cannot instantiate Shape directly.
- โ- Abstract class = partial implementation + shared state for one is-a family; cannot be instantiated.
- โ- Interface = a contract/capability with (traditionally) no state; a class can implement many.
- โ- Use an abstract class for shared code/identity, interfaces for orthogonal capabilities across unrelated types.