6. OOP & Polymorphism

Object-Oriented Principles, Interfaces & Polymorphism

Master Java's 4 Pillars of OOP (Encapsulation, Abstraction, Inheritance, Polymorphism), dynamic method dispatch, Abstract classes vs Interfaces, and pattern matching for instanceof.

🏛️ The 4 Pillars of Object-Oriented Programming

Java is designed around 4 core Object-Oriented Programming (OOP) paradigms:

  • Analogy: Architectural Prefab Modules & Universal Blueprint Contracts.
    • Encapsulation: Encasing engine wiring inside a sealed car hood. Drivers use exposed steering wheel pedals (public methods) without touching internal fuel injectors (private fields).
    • Abstraction: A TV remote control. You press the "Power On" button (abstract interface) without needing to understand radio frequency circuitry.
    • Inheritance: A basic Sedan car model serving as the foundation for a specialized Electric Sedan model (extends).
    • Polymorphism: Universal USB-C plugs. You can plug in a phone, laptop, or camera (Vehicle v); calling .charge() (v.startEngine()) executes the specific battery logic for that device!
                                  4 Pillars of OOP

        ┌───────────────────┬────────────┴────────────┬───────────────────┐
        ▼                   ▼                         ▼                   ▼
  Encapsulation        Abstraction               Inheritance          Polymorphism
Private Fields +     Interfaces &             Reuses Parent Code   Dynamic Method Dispatch
Public Accessors     Abstract Classes         via extends          via @Override

🔀 Polymorphism: Overloading vs. Overriding

MetricMethod Overloading (Compile-Time / Static)Method Overriding (Runtime / Dynamic)
Method SignatureSame method name; different parameter listsSame method name; identical parameter lists & return types
Class ScopeDefined within the same classDefined in Child subclass overriding Parent class method
Binding TimeResolved at Compile-Time by javacResolved at Runtime by JVM via vtable (Virtual Table) dispatch
AnnotationNoneMarked with @Override
// Method Overriding & Dynamic Polymorphism Demo
class Vehicle {
    public void startEngine() {
        System.out.println("Generic Vehicle Engine Started.");
    }
}

class ElectricCar extends Vehicle {
    @Override
    public void startEngine() {
        System.out.println("Silent Electric Motor Started.");
    }
}

public class PolymorphismDemo {
    public static void main(String[] args) {
        Vehicle myVehicle = new ElectricCar();
        // Dynamic Method Dispatch: Executes ElectricCar's overridden startEngine() at runtime!
        myVehicle.startEngine(); // Output: Silent Electric Motor Started.
    }
}

📑 Abstract Classes vs. Interfaces

                        Abstract Classes vs Interfaces

        ┌─────────────────────────────┴─────────────────────────────┐
        ▼                                                           ▼
Abstract Class (IS-A Relationship)                           Interface (CAN-DO Capability)
Supports state (instance fields)                             Stateless contracts (Java 8+ default/static methods)
Single inheritance (extends 1 class)                         Multiple inheritance (implements N interfaces)
// Interface with Default & Static Methods (Java 8+)
interface PaymentGateway {
    // Abstract contract method
    void processPayment(double amount);

    // Default method (Provides fallback implementation!)
    default void logTransaction(String txId) {
        System.out.println("Default Audit Log TX: " + txId);
    }

    // Static helper method
    static boolean isValidAmount(double amount) {
        return amount > 0;
    }
}

🔍 Modern Pattern Matching for instanceof (Java 16+)

Prior to Java 16, casting an object required verbose type checking and explicit casting. Pattern Matching for instanceof combines testing and casting into a single clean operation:

public class PatternMatchingDemo {
    public static void processShape(Object shape) {
        // Modern Java 16+ Pattern Matching for instanceof!
        if (shape instanceof String s) {
            System.out.println("String Length: " + s.length());
        } else if (shape instanceof Integer i && i > 100) {
            System.out.println("Large Integer: " + i);
        }
    }

    public static void main(String[] args) {
        processShape("Hello World");
        processShape(500);
    }
}

❓ Conceptual Quizzes

Knowledge Check

How does the JVM resolve overridden method calls at runtime during dynamic polymorphism?

Knowledge Check

What is the primary difference regarding state storage between an Abstract Class and an Interface in Java?


💻 Practice Problems

Problem: Polymorphic Payment Processing System

Design an interface PaymentProcessor with a method pay(double amount). Implement two classes CreditCardPayment and PayPalPayment. Write a static method executePayment(PaymentProcessor processor, double amount) that processes payments polymorphically.

On this page