Abstract Classes & Interfaces
Abstraction and interface implementation
Introduction to Abstraction
Basic Example
// Abstract class
public abstract class Animal {
protected String name;
public Animal(String name) {
this.name = name;
}
// Concrete method
public void sleep() {
System.out.println(name + " is sleeping");
}
// Abstract method
public abstract void makeSound();
}
class Dog extends Animal {
public Dog(String name) {
super(name);
}
@Override
public void makeSound() {
System.out.println(name + " barks!");
}
}
Benefits
- Reduces complexity
- Increases code reusability
- Supports polymorphism
- Enhances maintainability
Types of Abstraction
- Abstract Classes (0-100%)
- Interfaces (100%)
- Concrete Classes (0%)
Abstract Classes
Shape Example
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// Concrete method
public String getColor() {
return color;
}
// Abstract methods
public abstract double calculateArea();
public abstract void draw();
}
class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double calculateArea() {
return Math.PI * radius * radius;
}
@Override
public void draw() {
System.out.println("Drawing " + color + " circle");
}
}
Remember: Abstract methods cannot be private, static, or final.
Interfaces
Payment Interface Example
public interface PaymentProcessor {
// Constants
double MIN_AMOUNT = 0.01;
// Abstract methods
boolean processPayment(double amount);
boolean refund(String transactionId);
// Default method (Java 8+)
default boolean validateAmount(double amount) {
return amount >= MIN_AMOUNT;
}
// Static method (Java 8+)
static String formatCurrency(double amount) {
return String.format("$%.2f", amount);
}
}
class CreditCardProcessor implements PaymentProcessor {
@Override
public boolean processPayment(double amount) {
if (!validateAmount(amount)) {
return false;
}
System.out.println("Processing credit card payment: " +
PaymentProcessor.formatCurrency(amount));
return true;
}
@Override
public boolean refund(String transactionId) {
System.out.println("Refunding: " + transactionId);
return true;
}
}
Tip: Use interfaces for contracts and capabilities (CAN-DO relationships).
Abstract Classes vs Interfaces
| Aspect | Abstract Class | Interface |
|---|---|---|
| Keyword | abstract class | interface |
| Methods | Abstract + Concrete | Abstract + Default/Static |
| Variables | Instance variables | Constants only |
| Constructor | Yes | No |
| Inheritance | Single (extends) | Multiple (implements) |
Use Abstract Classes When:
- Sharing common code
- IS-A relationship
- Need constructors
- Protected/private members
Use Interfaces When:
- Defining contracts
- CAN-DO relationship
- Multiple inheritance needed
- Maximum flexibility
Best Practices
Interface Design
- Keep interfaces small and focused
- Use meaningful names
- Provide default implementations when helpful
- Document contracts clearly
Abstract Classes
- Use for template method pattern
- Provide common implementation
- Use protected for subclass access
- Consider final methods for invariants
Good Practice Example
// Good: Segregated interfaces
interface Worker {
void work();
}
interface Programmer extends Worker {
void code();
default void debug() {
System.out.println("Debugging...");
}
}
interface Designer extends Worker {
void design();
}
// Implementation can choose specific capabilities
class FullStackDeveloper implements Programmer, Designer {
@Override
public void work() {
code();
design();
}
@Override
public void code() {
System.out.println("Writing code");
}
@Override
public void design() {
System.out.println("Creating designs");
}
}
Avoid: Fat interfaces with too many methods (violates Interface Segregation Principle).
Summary - What We’ve Learned
Abstract Classes
- Provide partial abstraction (0-100%)
- Can contain both abstract and concrete methods
- Support constructors and instance variables
- Enable IS-A relationships with shared code
- Perfect for template method pattern
Interfaces
- Provide complete abstraction (100%)
- Support multiple inheritance
- Define contracts and capabilities
- Enable CAN-DO relationships
- Support default and static methods (Java 8+)
Design Principles
- Follow SOLID principles
- Keep interfaces small and focused
- Use meaningful names and documentation
- Choose based on relationship type
- Prioritize composition over inheritance
Core Concepts Mastered:
Abstraction, Polymorphism, Inheritance, Interface Segregation, Template Method, Multiple Inheritance
Common Interview Questions
Test your understanding with these frequently asked interview questions about abstract classes and interfaces.
Conceptual Questions
Coding Questions
Advanced Questions
Interview Tips
- Be Clear: Explain concepts with real-world examples
- Show Code: Be ready to write code snippets
- Discuss Trade-offs: Mention pros and cons of each approach
- Think SOLID: Reference design principles when relevant