CACS204 Object Oriented Programming in Java

Object Oriented Programming in JavaUnit 1110 min read

Abstract Classes & Interfaces: Definitions, Syntax, Real-World Use & Code Examples

Unit 11 of Object Oriented Programming in Java covers abstract classes (partial implementation, abstract keyword, constructors, methods) and interfaces (contracts, default/static methods, functional interfaces, implements), their syntax, inheritance rules, and how Java achieves multiple inheritance via interfaces. Incl

TAKEAWAYS:

  • Abstract classes partially implement a superclass (can have abstract methods + concrete methods) and cannot be instantiated; interfaces only define contracts (all methods abstract until Java 8) and cannot have instance variables (only public static final constants).
  • Java supports multiple inheritance through interfaces (a class can implement multiple interfaces but extend only one class).
  • Default methods in interfaces (Java 8+) allow adding new methods without breaking existing implementations; static methods provide utility functions.
  • Functional interfaces (interfaces with a single abstract method) are the basis of lambda expressions and stream APIs.
  • Key differences: abstract classes use extends, interfaces use implements; abstract classes can have constructors/instance variables, interfaces cannot (pre-Java 8).
  • Real-world use: WhatsApp’s Message hierarchy (abstract base class), Ncell’s PaymentGateway interface (multiple implementations like Khalti/Esewa), and Java’s Comparable/Comparator for sorting.

1. Abstract Classes: Definition and Syntax

An abstract class is a class that cannot be instantiated and is declared with the abstract keyword. It can contain:

  • Abstract methods (no body, declared with abstract).
  • Concrete methods (fully implemented).
  • Constructors (to initialize fields).
  • Instance variables and static members.

Why Use Abstract Classes?

  • To define a common structure for subclasses (e.g., Shape → Circle, Rectangle).
  • To enforce method implementation in subclasses (e.g., draw() must be defined).
  • To share code among related classes (e.g., Animal class with eat() method).

Syntax

abstract class AbstractClass {
    // Abstract method (no body)
    abstract void abstractMethod();

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

    // Constructor
    AbstractClass() {
        System.out.println("Abstract class constructor");
    }
}

Example: Vehicle Abstract Class

abstract class Vehicle {
    private String model;

    public Vehicle(String model) {
        this.model = model;
    }

    // Abstract method
    abstract void start();

    // Concrete method
    void displayModel() {
        System.out.println("Model: " + model);
    }
}

class Car extends Vehicle {
    public Car(String model) {
        super(model);
    }

    @Override
    void start() {
        System.out.println("Car started with key");
    }
}

State Diagram: Vehicle → Car Instantiation

classDiagram
    class Vehicle {
        -model: String
        +Vehicle(model: String)
        +start() abstract
        +displayModel()
    }
    class Car {
        +Car(model: String)
        +start()
    }
    Vehicle <|-- Car : Inherits

Real-World Example: WhatsApp’s Message System

WhatsApp uses an abstract Message class to define common behavior (e.g., send(), getTimestamp()), while subclasses like TextMessage, ImageMessage, and VoiceMessage implement their own render() methods. How it works:

  • All messages share Message’s fields (e.g., sender, timestamp).
  • Each subclass overrides render() to display differently (text vs. image preview).

2. Interfaces: Definition and Syntax

An interface is a pure contract (100% abstract) that defines what a class must do, not how. Before Java 8, all methods were public abstract. Since Java 8, interfaces can have:

  • default methods (with implementation).
  • static methods (utility functions).
  • private methods (helper methods, Java 9+).

Why Use Interfaces?

  • To achieve multiple inheritance (a class can implement multiple interfaces).
  • To define plug-and-play components (e.g., PaymentGateway for Khalti/Esewa).
  • To enforce method signatures without implementation (e.g., Comparable).

Syntax

interface InterfaceName {
    // Public abstract method (implicitly public abstract)
    void abstractMethod();

    // Default method (Java 8+)
    default void defaultMethod() {
        System.out.println("Default implementation");
    }

    // Static method (Java 8+)
    static void staticMethod() {
        System.out.println("Static utility method");
    }
}

Example: PaymentGateway Interface

interface PaymentGateway {
    void processPayment(double amount);

    // Default method (optional)
    default void refund(double amount) {
        System.out.println("Refunding: $" + amount);
    }
}

class KhaltiGateway implements PaymentGateway {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing via Khalti: $" + amount);
    }
}

class EsewaGateway implements PaymentGateway {
    @Override
    public void processPayment(double amount) {
        System.out.println("Processing via Esewa: $" + amount);
    }
}

State Diagram: Multiple Inheritance via Interfaces

classDiagram
    class PaymentGateway {
        +processPayment(amount: double)
        +refund(amount: double)
    }
    class KhaltiGateway {
        +processPayment(amount: double)
    }
    class EsewaGateway {
        +processPayment(amount: double)
    }
    PaymentGateway <|-- KhaltiGateway : Implements
    PaymentGateway <|-- EsewaGateway : Implements

Real-World Example: Ncell’s Payment Integration

Ncell’s app uses the PaymentGateway interface to support multiple payment methods (Khalti, Esewa, bank transfers). The app does not need to know which gateway is used—it just calls processPayment(). How it works:

  1. User selects payment method (Khalti/Esewa).
  2. App instantiates KhaltiGateway or EsewaGateway.
  3. processPayment() is called on the chosen object.

3. Key Differences: Abstract Class vs. Interface

Feature Abstract Class Interface
Instantiation Cannot be instantiated Cannot be instantiated
Methods Can have abstract + concrete methods All methods abstract (until Java 8)
Fields Can have instance + static variables Only public static final constants
Constructors Can have constructors No constructors
Inheritance Single inheritance (extends) Multiple inheritance (implements)
Use Case "Is-a" relationship (e.g., Car is a Vehicle) "Can-do" relationship (e.g., PaymentGateway can process payments)

When to Use Which?

  • Use an abstract class when:
    • You want to share code among related classes.
    • You need constructors or instance variables.
  • Use an interface when:
    • You need multiple inheritance.
    • You want to define a contract without implementation.

4. Functional Interfaces and Lambda Expressions

A functional interface is an interface with exactly one abstract method (SAM). It enables lambda expressions and method references.

Example: Runnable Functional Interface

@FunctionalInterface
interface Runnable {
    void run();
}

// Lambda expression
Runnable task = () -> System.out.println("Task running");

// Method reference
Runnable task2 = System::printTask;

Real-World Example: Java Streams

Java’s Stream API uses functional interfaces like Predicate, Function, and Consumer for operations like filter(), map(), and forEach(). Example:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
       .filter(n -> n % 2 == 0)  // Predicate<T>
       .forEach(System.out::println);  // Consumer<T>

State Diagram: Lambda Expression Evaluation

flowchart TD
    A["List<Integer> numbers = [1,2,3,4,5]"] --> B["numbers.stream()"]
    B --> C["filter(n -> n % 2 == 0)"]
    C --> D["{2, 4}"]
    D --> E["forEach(System.out::println)"]
    E --> F["Prints: 2\n4"]

5. Default and Static Methods in Interfaces

Default Methods

Allow adding new methods to interfaces without breaking existing implementations. Example:

interface Logger {
    void log(String message);

    default void logWithTimestamp(String message) {
        System.out.println(new Date() + ": " + message);
    }
}

class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println(message);
    }
    // logWithTimestamp() is inherited
}

Static Methods

Provide utility functions that can be called without an instance. Example:

interface MathUtils {
    static int max(int a, int b) {
        return a > b ? a : b;
    }
}

// Usage
int result = MathUtils.max(5, 10);  // No interface instance needed

6. Multiple Inheritance via Interfaces

Java does not support multiple inheritance of classes (to avoid the "diamond problem"), but it supports multiple inheritance of interfaces. Example:

interface Flyable {
    void fly();
}

interface Swimmable {
    void swim();
}

class Duck implements Flyable, Swimmable {
    @Override
    public void fly() {
        System.out.println("Duck flying");
    }

    @Override
    public void swim() {
        System.out.println("Duck swimming");
    }
}

Real-World Example: Daraz’s Order Processing

Daraz’s order system uses interfaces to handle multiple payment and shipping methods:

  • PaymentProcessor (Khalti, Esewa, bank transfer).
  • ShippingService (Nepal Post, Kanti Path, Pathao). An Order class can implement both:
class Order implements PaymentProcessor, ShippingService {
    // ...
}

7. Exam Tip: How to Score Full Marks

  1. Define Clearly:

    • Abstract class: "A class declared with abstract that cannot be instantiated and may contain abstract methods."
    • Interface: "A reference type with only abstract methods (pre-Java 8) that defines a contract for classes to implement."
  2. Code Examples:

    • Always provide full code with abstract/interface keywords.
    • Show inheritance (extends/implements) and method overriding.
  3. Comparisons:

    • Use a table (as above) to highlight differences between abstract classes and interfaces.
  4. Real-World Scenarios:

    • Link to Nepali apps (e.g., WhatsApp’s Message hierarchy, Ncell’s PaymentGateway).
    • Explain why an interface/abstract class is used (e.g., "to support multiple payment methods").
  5. Common Pitfalls:

    • Interfaces cannot have instance variables (only public static final constants).
    • Abstract classes can have constructors, but interfaces cannot.
    • Multiple inheritance is only possible via interfaces, not classes.
  6. Diagrams:

    • Draw UML class diagrams for inheritance/interfaces.
    • Show state changes (e.g., after implements or extends).

Based on the TU BCA syllabus for Object Oriented Programming in Java (CACS204), unit 11.

Discussion

Loading…