Abstract Classes

Introduction

Abstract class is a class that cannot be instantiated and may contain abstract methods (methods without body).


Syntax

abstract class ClassName {
    // Abstract method (no body)
    abstract returnType methodName();

    // Concrete method (with body)
    returnType method2() {
        // Implementation
    }
}

Basic Example

abstract class Animal {
    // Abstract method
    abstract void sound();

    // Concrete method
    void sleep() {
        System.out.println("Sleeping...");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Bark");
    }
}

class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("Meow");
    }
}

public class Main {
    public static void main(String[] args) {
        // Animal a = new Animal();  // ✗ Error: Cannot instantiate

        Animal dog = new Dog();
        dog.sound();  // Bark
        dog.sleep();  // Sleeping...

        Animal cat = new Cat();
        cat.sound();  // Meow
        cat.sleep();  // Sleeping...
    }
}

Rules for Abstract Classes

  1. Cannot instantiate abstract class
  2. Can have abstract and concrete methods
  3. Can have constructors
  4. Can have fields
  5. Can have static methods
  6. Abstract method must be in abstract class
  7. Subclass must implement all abstract methods
  8. If subclass doesn’t implement, it must also be abstract

Abstract Methods

abstract class Shape {
    String color;

    // Abstract methods (no implementation)
    abstract double area();
    abstract double perimeter();

    // Concrete method
    void displayColor() {
        System.out.println("Color: " + color);
    }
}

class Circle extends Shape {
    double radius;

    Circle(String color, double radius) {
        this.color = color;
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * radius * radius;
    }

    @Override
    double perimeter() {
        return 2 * Math.PI * radius;
    }
}

class Rectangle extends Shape {
    double length, width;

    Rectangle(String color, double length, double width) {
        this.color = color;
        this.length = length;
        this.width = width;
    }

    @Override
    double area() {
        return length * width;
    }

    @Override
    double perimeter() {
        return 2 * (length + width);
    }
}

public class Main {
    public static void main(String[] args) {
        Shape circle = new Circle("Red", 5);
        System.out.println("Circle Area: " + circle.area());
        circle.displayColor();

        Shape rect = new Rectangle("Blue", 4, 6);
        System.out.println("Rectangle Area: " + rect.area());
        rect.displayColor();
    }
}

Abstract Class with Constructor

abstract class Employee {
    String name;
    double salary;

    // Constructor
    Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
        System.out.println("Employee constructor");
    }

    abstract void work();

    void displayInfo() {
        System.out.println("Name: " + name);
        System.out.println("Salary: " + salary);
    }
}

class Manager extends Employee {
    String department;

    Manager(String name, double salary, String department) {
        super(name, salary);  // Call abstract class constructor
        this.department = department;
    }

    @Override
    void work() {
        System.out.println(name + " manages " + department);
    }
}

public class Main {
    public static void main(String[] args) {
        Manager mgr = new Manager("John", 50000, "IT");
        mgr.displayInfo();
        mgr.work();
    }
}

Partial Implementation

abstract class Vehicle {
    String brand;

    abstract void start();
    abstract void stop();

    // Common implementation
    void displayBrand() {
        System.out.println("Brand: " + brand);
    }
}

abstract class FourWheeler extends Vehicle {
    // Implement one method
    @Override
    void start() {
        System.out.println("Four wheeler starting");
    }

    // stop() still abstract
}

class Car extends FourWheeler {
    Car(String brand) {
        this.brand = brand;
    }

    @Override
    void stop() {
        System.out.println("Car stopping");
    }
}

public class Main {
    public static void main(String[] args) {
        Car car = new Car("Toyota");
        car.start();
        car.stop();
        car.displayBrand();
    }
}

Complete Example: Bank System

abstract class BankAccount {
    protected String accountNumber;
    protected String holderName;
    protected double balance;

    BankAccount(String accountNumber, String holderName) {
        this.accountNumber = accountNumber;
        this.holderName = holderName;
        this.balance = 0;
    }

    // Abstract methods
    abstract void deposit(double amount);
    abstract boolean withdraw(double amount);
    abstract double calculateInterest();

    // Concrete methods
    void displayBalance() {
        System.out.println("Balance: " + balance);
    }

    void displayInfo() {
        System.out.println("Account: " + accountNumber);
        System.out.println("Holder: " + holderName);
        displayBalance();
    }
}

class SavingsAccount extends BankAccount {
    private double interestRate = 4.5;
    private double minimumBalance = 1000;

    SavingsAccount(String accountNumber, String holderName) {
        super(accountNumber, holderName);
    }

    @Override
    void deposit(double amount) {
        balance += amount;
        System.out.println("Deposited: " + amount);
    }

    @Override
    boolean withdraw(double amount) {
        if (balance - amount >= minimumBalance) {
            balance -= amount;
            System.out.println("Withdrawn: " + amount);
            return true;
        }
        System.out.println("Insufficient balance. Minimum required: " + minimumBalance);
        return false;
    }

    @Override
    double calculateInterest() {
        return balance * interestRate / 100;
    }
}

class CurrentAccount extends BankAccount {
    private double overdraftLimit = 5000;

    CurrentAccount(String accountNumber, String holderName) {
        super(accountNumber, holderName);
    }

    @Override
    void deposit(double amount) {
        balance += amount;
        System.out.println("Deposited: " + amount);
    }

    @Override
    boolean withdraw(double amount) {
        if (balance + overdraftLimit >= amount) {
            balance -= amount;
            System.out.println("Withdrawn: " + amount);
            return true;
        }
        System.out.println("Overdraft limit exceeded");
        return false;
    }

    @Override
    double calculateInterest() {
        return 0;  // No interest on current account
    }
}

public class Main {
    public static void main(String[] args) {
        SavingsAccount savings = new SavingsAccount("SA1001", "John");
        savings.deposit(10000);
        savings.withdraw(2000);
        System.out.println("Interest: " + savings.calculateInterest());
        savings.displayInfo();

        System.out.println();

        CurrentAccount current = new CurrentAccount("CA2001", "Alice");
        current.deposit(5000);
        current.withdraw(8000);  // Uses overdraft
        current.displayInfo();
    }
}

Why Use Abstract Classes?

  1. Enforce contract: Subclasses must implement abstract methods
  2. Code reuse: Share common code in concrete methods
  3. Partial implementation: Provide some default behavior
  4. Template: Define structure for subclasses
  5. Polymorphism: Use abstract class reference

Abstract vs Concrete

// Abstract class
abstract class AbstractExample {
    abstract void method1();  // No body

    void method2() {          // Has body
        System.out.println("Concrete method");
    }
}

// Concrete class
class ConcreteExample {
    void method1() {  // Must have body
        System.out.println("Method 1");
    }

    void method2() {
        System.out.println("Method 2");
    }
}

Abstract Class with Static

abstract class MathOperations {
    // Static method in abstract class
    static int add(int a, int b) {
        return a + b;
    }

    // Abstract method
    abstract int multiply(int a, int b);
}

class Calculator extends MathOperations {
    @Override
    int multiply(int a, int b) {
        return a * b;
    }
}

public class Main {
    public static void main(String[] args) {
        // Call static method without object
        System.out.println("Sum: " + MathOperations.add(10, 20));

        Calculator calc = new Calculator();
        System.out.println("Product: " + calc.multiply(10, 20));
    }
}

Multiple Abstract Methods

abstract class Payment {
    abstract void validatePayment();
    abstract void processPayment();
    abstract void sendReceipt();

    // Template method
    final void makePayment() {
        validatePayment();
        processPayment();
        sendReceipt();
    }
}

class CreditCardPayment extends Payment {
    @Override
    void validatePayment() {
        System.out.println("Validating credit card");
    }

    @Override
    void processPayment() {
        System.out.println("Processing credit card payment");
    }

    @Override
    void sendReceipt() {
        System.out.println("Sending email receipt");
    }
}

Comparison Table

FeatureAbstract ClassConcrete Class
InstantiationCannot create objectsCan create objects
Abstract methodsCan haveCannot have
Concrete methodsCan haveMust have all
KeywordabstractNo keyword
PurposePartial implementationFull implementation
InheritanceCan be extendedCan be extended

Abstract vs Interface

FeatureAbstract ClassInterface
MethodsAbstract + ConcreteAbstract (Java 7), can have default (Java 8+)
VariablesAny typepublic static final only
ConstructorYesNo
InheritanceSingleMultiple
Access modifiersAnypublic only (methods)
When to useIS-A + shared codeCAN-DO capability

Quick Reference

// Abstract class
abstract class Parent {
    // Fields
    int x;

    // Constructor
    Parent() { }

    // Abstract method (no body)
    abstract void method1();

    // Concrete method (with body)
    void method2() {
        System.out.println("Concrete");
    }
}

// Concrete subclass
class Child extends Parent {
    @Override
    void method1() {  // Must implement
        System.out.println("Implemented");
    }
}

// Usage
// Parent p = new Parent();  // ✗ Error
Parent p = new Child();  // ✓ OK

Exam Tips

Remember:

  1. Cannot instantiate abstract class
  2. Use abstract keyword
  3. Can have abstract and concrete methods
  4. Abstract method has no body
  5. Subclass must implement all abstract methods
  6. Can have constructor
  7. Can have fields and static methods
  8. Used for partial implementation
  9. Enforces contract for subclasses
  10. Enables polymorphism

Common Questions:

  • What is abstract class?
  • Can we create object of abstract class?
  • Abstract class vs interface?
  • Can abstract class have constructor?
  • What are abstract methods?
  • Why use abstract classes?
  • Can abstract class have concrete methods?
  • Rules for abstract classes?