IT234 Object Oriented Programming with Java

Object Oriented Programming with JavaUnit 511 min read

Interfaces, Abstract Classes & Polymorphism in Java

Unit 5 of Object Oriented Programming with Java covers interfaces (contracts, multiple inheritance, default/static methods), abstract classes (partial implementation, abstract methods), and their real-world applications in designing flexible, reusable code. Learn how to use them to enforce structure, achieve polymorphi

TAKEAWAYS:

  • Interfaces define what a class can do (methods) without specifying how, enabling multiple inheritance of type.
  • Abstract classes provide partial implementation (fields + some methods) and enforce is-a relationships via abstract methods.
  • Default methods in interfaces allow adding new functionality without breaking existing implementations.
  • Polymorphism via interfaces/abstract classes lets you write code that works with any implementing class (e.g., List<String> for ArrayList or LinkedList).
  • Key difference: Interfaces are for capability ("can fly"), abstract classes for inheritance ("is a vehicle").
  • Real-world use: APIs (e.g., Comparable, Serializable), frameworks (Spring’s @Transactional), and design patterns (Strategy, Observer).

1. Interfaces: Contracts for Behavior

An interface is a reference type that defines a set of methods a class must implement, but provides no implementation itself. It enforces a contract that classes must follow.

Syntax and Key Features

public interface Flyable {
    // Abstract method (implicitly public abstract)
    void fly();

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

    // Static method (Java 8+)
    static void takeOff() {
        System.out.println("Preparing for takeoff.");
    }
}
  • All methods are public abstract by default (no access modifiers or abstract keyword needed).
  • Default methods allow adding new methods without breaking existing implementations.
  • Static methods provide utility functions tied to the interface (e.g., Collections.sort() uses Comparable).

Why Use Interfaces?

Feature Interface Abstract Class
Inheritance Multiple (class A implements X, Y) Single (class A extends B)
Fields Only public static final (constants) Can have instance variables
Constructors No constructors Can have constructors
Purpose "Can do" (e.g., Runnable, Serializable) "Is a" (e.g., AbstractList)

Example: Comparable Interface

public class Student implements Comparable<Student> {
    private String name;
    private int rollNo;

    @Override
    public int compareTo(Student other) {
        return this.rollNo - other.rollNo; // Sort by roll number
    }
}

Use Case: Sorting a list of Student objects:

List<Student> students = new ArrayList<>();
students.sort(null); // Uses Comparable.compareTo()


2. Implementing Interfaces

A class implements an interface using the implements keyword and provides concrete implementations for all abstract methods.

Example: Flyable Interface

public class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("Bird is flying with wings.");
    }
}

public class Drone implements Flyable {
    @Override
    public void fly() {
        System.out.println("Drone is flying with propellers.");
    }
}

Polymorphism in Action:

Flyable[] flyers = {new Bird(), new Drone()};
for (Flyable flyer : flyers) {
    flyer.fly(); // Calls the correct implementation
}

Output:

Bird is flying with wings.
Drone is flying with propellers.

MERMAID FLOWCHART:

flowchart TD
    A["Flyable interface"] -->|"implements"| B["Bird class"]
    A -->|"implements"| C["Drone class"]
    B -->|"fly()"| D["Prints: Bird is flying..."]
    C -->|"fly()"| E["Prints: Drone is flying..."]
    F["Flyable[] flyers"] -->|"polymorphic call"| D
    F -->|"polymorphic call"| E

3. Default and Static Methods

Default Methods

  • Allow adding new methods to interfaces without breaking existing implementations.
  • Use the default keyword and provide a body.

Example: Adding land() to Flyable:

public interface Flyable {
    void fly();
    default void land() {
        System.out.println("Landing safely.");
    }
}

Conflict Resolution: If a class implements two interfaces with the same default method, it must override it.

public class Parrot implements Flyable, Swimmable {
    @Override
    public void land() {
        System.out.println("Parrot lands on a branch.");
    }
}

Static Methods

  • Belong to the interface itself, not instances.
  • Called using the interface name (e.g., Flyable.takeOff()).

Example: takeOff() in Flyable:

public interface Flyable {
    static void takeOff() {
        System.out.println("Preparing for takeoff...");
    }
}
Flyable.takeOff(); // Output: Preparing for takeoff...

MERMAID STATE DIAGRAM:


4. Abstract Classes: Partial Implementation

An abstract class is a class that cannot be instantiated and may contain abstract methods (no body) and concrete methods (with body). It provides a partial implementation.

Syntax

public abstract class Vehicle {
    private String model;

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

    // Abstract method (no body)
    public abstract void start();

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

Key Points:

  • Can have constructors, fields, and methods with bodies.
  • Cannot be instantiated (new Vehicle() is invalid).
  • Used for shared code among related classes (e.g., Animal → Dog, Cat).

Example: Vehicle Hierarchy

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

```figure
{"type":"tree","root":{"v":"Vehicle (Abstract)","children":[{"v":"Car","children":[{"v":"ElectricCar"}]},{"v":"Truck"}]},"caption":"Inheritance hierarchy showing abstract base class and concrete subclasses"}
@Override
public void start() {
    System.out.println("Car engine started.");
}

}

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

@Override
public void start() {
    System.out.println("Bike kick-started.");
}

}

**Usage**:
```java
Vehicle car = new Car("Toyota");
car.start(); // Output: Car engine started.
car.displayModel(); // Output: Model: Toyota


5. Interfaces vs. Abstract Classes: When to Use Which

Scenario Use Interface Use Abstract Class
Multiple inheritance needed ✅ (e.g., class Bat implements Flyable, Swimmable) ❌ (Java doesn’t support multiple inheritance)
Defining a capability ✅ (e.g., Runnable, Comparable) ❌
Shared code among subclasses ❌ ✅ (e.g., AbstractList in Java Collections)
Non-instantiable base class ❌ (unless all methods are abstract) ✅ (e.g., AbstractMap)
Default behavior for new methods ✅ (default methods) ❌

MERMAID DECISION TREE:

flowchart TD
    A["Need multiple inheritance?"] -->|"Yes"| B["Use Interface"]
    A -->|"No"| C["Shared code needed?"]
    C -->|"Yes"| D["Use Abstract Class"]
    C -->|"No"| E["Defining a capability?"]
    E -->|"Yes"| B
    E -->|"No"| F["Non-instantiable base?"]
    F -->|"Yes"| D
    F -->|"No"| G["Use Interface or Class"]

6. Real-World Applications

In the Real World

  1. Khalti Payment System

    • Uses interfaces like PaymentGateway to support multiple payment methods (e.g., CreditCardPayment, MobileWalletPayment).
    • How: The PaymentProcessor class depends on PaymentGateway, allowing new payment methods (e.g., UPI) without modifying existing code.
  2. Pathao Driver App

    • Implements LocationUpdater interface for GPS tracking.
    • How: Different transport modes (Bike, Car, Auto) implement LocationUpdater.updateLocation() to send real-time coordinates to the server.
  3. Nepal Stock Exchange (NEPSE)

    • Uses TradingStrategy interface for algorithmic trading.
    • How: Strategies like MovingAverageStrategy or VolumeWeightedStrategy implement executeTrade() without coupling to a specific exchange.

WORKED EXAMPLE: NTC Traffic Route Optimization Assume NTC uses interfaces to manage traffic routes dynamically:

public interface TrafficRoute {
    void optimizeRoute();
}

public class HighwayRoute implements TrafficRoute {
    @Override
    public void optimizeRoute() {
        System.out.println("Optimizing via highways (fastest).");
    }
}

public class LocalRoute implements TrafficRoute {
    @Override
    public void optimizeRoute() {
        System.out.println("Optimizing via local roads (less traffic).");
    }
}

Usage in NTC System:

TrafficRoute route = new LocalRoute(); // Depends on traffic conditions
route.optimizeRoute(); // Output: Optimizing via local roads...

Visualization:

flowchart TD
    A["NTC Traffic System"] -->|"uses"| B["TrafficRoute interface"]
    B -->|"implemented by"| C["HighwayRoute"]
    B -->|"implemented by"| D["LocalRoute"]
    A -->|"calls"| C
    A -->|"calls"| D

7. Exam Tip

  1. Interface vs. Abstract Class:

    • Exam loves: Asking you to choose between the two for a given scenario. Remember:
      • Can a class extend multiple abstract classes? → No (Java doesn’t support multiple inheritance).
      • Can a class implement multiple interfaces? → Yes.
    • Common Pitfall: Forgetting to implement all abstract methods in a class.
  2. Default Method Conflicts:

    • If two interfaces have the same default method, the implementing class must override it. This is a frequent exam question.
  3. Polymorphism:

    • Always test your code with polymorphism. For example:
      List<String> list = new ArrayList<>(); // Polymorphism: List interface, ArrayList implementation
      
    • Exam Question: Given a hierarchy, write code to demonstrate polymorphism.
  4. Abstract Methods:

    • An abstract class can have abstract methods, but does not have to. If it has at least one abstract method, it must be declared abstract.
  5. Static Methods in Interfaces:

    • Can be called without an instance (e.g., Collections.sort() uses Comparable’s static utility methods).

PRACTICE QUESTION:

interface A {
    void show();
    default void display() { System.out.println("A"); }
}

interface B extends A {
    void show();
    default void display() { System.out.println("B"); }
}

class C implements B {
    public void show() { System.out.println("C"); }
    // No override for display() → Compile-time error!
}

Why does this fail?

  • Answer: Class C implements B, which extends A. Both A and B have a default method display(). Since C does not override display(), the compiler cannot decide which default method to use. Always override default methods in conflicts.

MERMAID ERROR FLOW:

flowchart TD
    A["Class C implements B"] --> B["B extends A"]
    B --> C["A has default display()"]
    B --> D["B has default display()"]
    D --> E["Conflict: No override in C"]
    E --> F["Compile-time Error"]

Based on the TU BIM syllabus for Object Oriented Programming with Java (IT234), unit 5.

Discussion

Loading…