CSC409 Advanced Java Programming

Advanced Java ProgrammingUnit 1010 min read

OOP Features & Advanced Topics: Inheritance, Polymorphism, Abstraction, Interfaces, Nested Classes & Design Patterns

Unit 10 of Advanced Java Programming explores core OOP principles (inheritance, polymorphism, abstraction, interfaces) and advanced constructs (nested classes, design patterns) with real-world applications in Nepalese tech (eSewa, Ncell) and global systems (Google Maps). Includes code examples, execution traces, and co

Core OOP Principles in Java

1. Inheritance: Code Reusability & Hierarchy

Inheritance allows a subclass (child) to inherit fields/methods from a superclass (parent). Java supports single-level, multilevel, hierarchical, and multiple inheritance via interfaces.

How It Works

class Vehicle {  // Superclass
    String brand;
    void display() { System.out.println("Brand: " + brand); }
}

class Car extends Vehicle {  // Subclass
    String model;
    void showModel() { System.out.println("Model: " + model); }
}

Execution Trace:

Step Action Output
1 Car myCar = new Car(); Object created
2 myCar.brand = "Toyota"; brand inherited
3 myCar.model = "Corolla"; model added in Car
4 myCar.display(); Brand: Toyota
5 myCar.showModel(); Model: Corolla

Types of Inheritance

classDiagram
    class Vehicle {
        <<abstract>>
        +String brand
        +display()
    }
    class Car {
        +String model
        +showModel()
    }
    class Bike {
        +int speed
        +accelerate()
    }
    Vehicle <|-- Car
    Vehicle <|-- Bike
    Car --> Bike : "Hierarchical (Incorrect: Should be separate)"
    note for Car "Extends Vehicle"
    note for Bike "Extends Vehicle"
Corrected class diagram showing hierarchical inheritance (no direct relationship between Car and Bike)

Real-World Example:

  • eSewa’s Payment System:
    • Superclass: Payment (fields: amount, transactionId; method: process()).
    • Subclasses: OnlinePayment (extends Payment, adds cardDetails), CashPayment (extends Payment, adds receiptId).
    • Why? Avoids rewriting process() logic for each payment type.

2. Polymorphism: "One Interface, Many Forms"

Polymorphism enables method overriding (runtime) and method overloading (compile-time).

Method Overriding

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

State After Execution:

Method Overloading

class Calculator {
    int add(int a, int b) { return a + b; }
    double add(double a, double b) { return a + b; }
}

Comparison Table:

Feature Overriding Overloading
Binding Runtime (Dynamic) Compile-time (Static)
Parameters Same signature Different signatures
Return Type Can be covariant Must differ
Use Case Extending functionality Multiple operations
12345678910468101214161820yadd(int x)add(double x)
Visualizing method overloading with different parameter types

Real-World Example:

  • Ncell’s Billing System:
    • Overloading: calculateBill(int minutes) vs. calculateBill(int minutes, int dataUsage).
    • Overriding: Customer (base) has generateBill(), while PremiumCustomer overrides it to include discounts.

3. Abstraction: Hiding Implementation

Abstraction is achieved via abstract classes and interfaces.

Abstract Class

abstract class Shape {
    abstract double area();  // No body
    void display() { System.out.println("Shape"); }  // Concrete
}
class Circle extends Shape {
    double radius;
    @Override double area() { return 3.14 * radius * radius; }
}

State After Circle c = new Circle(); c.area();:

classDiagram
    class Shape {
        <<abstract>>
        +abstract double area()
    }
    class Circle {
        +double radius
        +double area()
    }
    Shape <|-- Circle
    note for Circle "Concrete implementation of area()"
Class diagram showing abstract Shape and concrete Circle with area() method

Interfaces

interface Drivable {
    void start();
    void stop();
}
class Car implements Drivable {
    public void start() { System.out.println("Engine starts"); }
    public void stop() { System.out.println("Engine stops"); }
}

Key Differences:

Abstract Class Interface
Can have constructors No constructors
Can have non-final fields Only public static final fields
Supports partial implementation Fully abstract until Java 8
ShapeCircleRectangle
Multiple classes implementing the same interface (Shape)

Real-World Example:

  • Pathao’s Ride System:
    • Interface: PaymentMethod (methods: processPayment()).
    • Implementations: CreditCardPayment, CashPayment, KhaltiPayment.
    • Why? Ensures all payment methods follow the same contract.

4. Nested Classes & Inner Classes

Nested classes improve encapsulation and scope control.

Types

  1. Static Nested Class:
    class Outer {
        static class Nested {
            void display() { System.out.println("Static Nested"); }
        }
    }
    
  2. Inner Class (Non-static):
    class Outer {
        class Inner {
            void display() { System.out.println("Inner Class"); }
        }
    }
    
  3. Anonymous Class:
    Runnable r = new Runnable() {
        public void run() { System.out.println("Anonymous Runnable"); }
    };
    
  4. Local Class:
    void method() {
        class Local { void show() { System.out.println("Local Class"); } }
        Local l = new Local();
        l.show();
    }
    

Real-World Example:

  • Google Maps’ Route Planner:
    • Outer class: Map.
    • Inner class: RouteCalculator (accesses Map's private locations list).
    • Why? Avoids exposing locations to external classes.

5. Design Patterns in Java

Design patterns are reusable solutions to common problems.

Singleton Pattern (Ensures One Instance)

class Database {
    private static Database instance;
    private Database() {}  // Private constructor
    public static Database getInstance() {
        if (instance == null) instance = new Database();
        return instance;
    }
}

Execution Trace:

Step Action State of instance
1 Database db1 = getInstance() instance created
2 Database db2 = getInstance() Same instance returned

Real-World Example:

  • NEPSE’s Trading System:
    • Singleton Market class ensures only one instance manages stock prices.

Factory Pattern (Object Creation)

interface Vehicle {
    void drive();
}
class Car implements Vehicle { public void drive() { System.out.println("Driving Car"); } }
class Bike implements Vehicle { public void drive() { System.out.println("Riding Bike"); } }

class VehicleFactory {
    public Vehicle getVehicle(String type) {
        if (type.equals("car")) return new Car();
        else return new Bike();
    }
}

State After VehicleFactory factory = new VehicleFactory(); factory.getVehicle("car");:

classDiagram
    class VehicleFactory {
        +Vehicle getVehicle(String type)
    }
    class Vehicle {
        <<abstract>>
        +abstract void drive()
    }
    class Car {
        +void drive()
    }
    VehicleFactory --> Car : "Creates"
    note for Car "Output: Driving Car"
Factory pattern diagram showing object creation flow

Real-World Example:

  • eSewa’s Payment Factory:
    • PaymentFactory.createPayment("khalti") returns KhaltiPayment object.

In the Real World

  1. Khalti’s Payment Gateway:

    • Polymorphism: Uses interfaces like PaymentProcessor with implementations (CreditCardProcessor, KhaltiProcessor).
    • Singleton: Ensures one TransactionLogger instance across all payments.
  2. Daraz’s Order Queue:

    • Priority Queue (via PriorityQueue class): Orders are processed based on priority (e.g., "Express" > "Standard").
    • State After Adding Orders:
Express Order 1Standard Order 1Express Order 2FRONTREARoutin
Priority Queue state after adding orders (Express > Standard)
  1. Ncell’s Billing System:
    • Strategy Pattern: Different billing strategies (PrepaidStrategy, PostpaidStrategy) selected at runtime.
    • Code Snippet:
      interface BillingStrategy { double calculateBill(int usage); }
      class PrepaidStrategy implements BillingStrategy { ... }
      class PostpaidStrategy implements BillingStrategy { ... }
      

Exam Tip

  1. Inheritance Questions:

    • Always show UML diagrams for class hierarchies.
    • Compare Java’s single inheritance with C++’s multiple inheritance.
  2. Polymorphism:

    • For overriding, trace method calls at runtime (e.g., Animal a = new Dog(); a.sound(); → Bark!).
    • For overloading, list all method signatures in the answer.
  3. Abstraction:

    • Abstract classes = "partial blueprint" (can have concrete methods).
    • Interfaces = "full contract" (Java 8+ allows default methods).
  4. Design Patterns:

    • Singleton: Emphasize private constructor + static getter.
    • Factory: Show interface + concrete classes + factory method.
  5. Nested Classes:

    • Anonymous classes are often used in event handling (e.g., button clicks in Swing).
    • Local classes are useful for short-lived objects (e.g., inside a method).
  6. Real-World Mapping:

    • Relate eSewa’s payment to Strategy Pattern.
    • Relate Ncell’s billing to Method Overloading/Overriding.

Pro Tip: For coding questions (e.g., "Create a Distance class"), always:

  1. Declare private fields.
  2. Use constructors for initialization.
  3. Implement getters/setters if needed.
  4. Add methods for operations (e.g., add(), compare()).

Based on the TU BSc CSIT syllabus for Advanced Java Programming (CSC409), unit 10.

Discussion

Loading…