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

AspectAbstract ClassInterface
Keywordabstract classinterface
MethodsAbstract + ConcreteAbstract + Default/Static
VariablesInstance variablesConstants only
ConstructorYesNo
InheritanceSingle (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