Basics of OOP

Pillars of OOP

Abstraction - Hiding the implementation complexity (abstract methods, interfaces)

How it works: In Java, Abstraction is realized primarily through two tools:

  1. Abstract Classes: Define a common structure (shared attributes/methods) but leave some implementation details to subclasses. You cannot instantiate an abstract class.
  2. Interfaces: Define a strict contract (what methods must exist) without defining any implementation (mostly).
// 1. The Abstraction
abstract class Shape {
    String color;

    // We know every shape has an area, but we don't know how to calculate it yet.
    // This is the abstraction.
    abstract double calculateArea(); 
}

// 2. The Concrete Implementation
class Rectangle extends Shape {
    double length;
    double width;

    // We MUST implement the abstract method here
    @Override
    double calculateArea() {
        return length * width;
    }
}

// Usage
public class Main {
    public static void main(String[] args) {
        // Shape s = new Shape(); // ❌ ILLEGAL: You cannot create an instance of an abstraction.
        Shape s = new Rectangle(); // ✅ LEGAL: You treat the specific object as its abstraction.
    }
}

Encapsulation - Hiding the data (private fields, public getters). Encapsulation is about bundling (syntax).

How:

Bad Design (No Encapsulation): Any random class can bankrupt you.

class BankAccount {
    public double balance; // ❌ DANGEROUS: Public access
}

// Client code
account.balance = -1000000; // The bank is now broken.

Good Design (Encapsulated): You control how the state changes.

class BankAccount {
    // 1. Data is hidden
    private double balance; 

    public BankAccount(double initialBalance) {
        if (initialBalance >= 0) {
            this.balance = initialBalance;
        }
    }

    // 2. Methods control mutation
    public void deposit(double amount) {
        if (amount > 0) {
            this.balance += amount;
        }
    }

    public void withdraw(double amount) {
        // 3. Validation Logic (Invariant)
        if (amount > 0 && amount <= balance) {
            this.balance -= amount;
        } else {
            System.out.println("Insufficient funds or invalid amount!");
        }
    }

    // Getter allows read-only access
    public double getBalance() {
        return balance;
    }
}

Encapsulation is not just getters and setters. If you have a private field and you auto-generate a get and set for it without any logic, you have effectively made it public. True encapsulation involves hiding information that the client doesn't need to know.


Inheritance - Code Reuse

"Why":

"How":

Code Example (The Traffic System)

The Parent (Generalization):

// The Parent Class
class Vehicle {
    protected int speed; // protected = accessible by children

    public void accelerate() {
        speed += 10;
        System.out.println("Moving at " + speed + " km/h");
    }
}

The Children (Specialization):

// The Child Class
class Car extends Vehicle {
    private int fuelLevel;

    public void honk() {
        System.out.println("Beep beep!");
    }
}

// Another Child
class Bicycle extends Vehicle {
    public void ringBell() {
        System.out.println("Ring ring!");
    }
    
    // Overriding behavior
    @Override
    public void accelerate() {
        speed += 2; // Bikes are slower
        System.out.println("Pedaling at " + speed + " km/h");
    }
}

image.png

The Golden Rule for Patterns:

"Favor Composition over Inheritance."

Conspect/Script Summary:

Feature Abstraction Inheritance
Focus Design / Interface Implementation / Reuse
Question "What services do you offer?" "How can I avoid rewriting code?"
Java Tool interfaceabstract methods extends
Relationship "Can-Do" (Contract) "Is-A" (Hierarchy)

Polymorphism


Inheritance & Abstraction

The Analogy

The Code Showdown

Here is a scenario where we use both, but I will label which part is which.

// 1. ABSTRACTION
// We hide the complexity of "how" an animal makes sound.
// We just define the CONTRACT.
abstract class Animal {
    // This is pure Abstraction. 
    // We force the child to decide "how".
    abstract void makeSound(); 

    // 2. INHERITANCE
    // This is concrete logic (Implementation).
    // All children get this code for free. Reusability!
    void sleep() {
        System.out.println("Zzzzz...");
    }
}

class Dog extends Animal {
    // Implementing the Abstraction
    @Override
    void makeSound() {
        System.out.println("Bark!");
    }
}

class Cat extends Animal {
    // Implementing the Abstraction
    @Override
    void makeSound() {
        System.out.println("Meow!");
    }
    // It inherits sleep() automatically.
}

Information hiding. IH is about dependency (design).

"Why":

"How":

  1. Minimize Visibility: Use visibility modifiers (privateprotected) aggressively.
  2. Public Interface: Only public methods should be used to modify a class's attributes.

Code Example (Bad vs. Good):


Information hiding & Encapsulation

The Nuance: You can have Encapsulation without proper Information Hiding.

The "Leaky Abstraction" Example

Imagine you are building a Wallet class.

Scenario A: Encapsulation ✅ | Information Hiding ❌ Here, we use private fields (Encapsulation is technically present), but we leak the internal implementation details to the world.

public class Wallet {
    // Encapsulation: The field is private.
    private ArrayList<Cash> moneyList; 

    public Wallet() {
        this.moneyList = new ArrayList<>();
    }

    // VIOLATION OF INFORMATION HIDING:
    // 1. You are forcing the client to know you use an 'ArrayList'. 
    //    If you switch to 'LinkedList' later, the client code breaks.
    // 2. You return the ACTUAL list. The client can clear() it 
    //    without the Wallet knowing.
    public ArrayList<Cash> getMoneyList() {
        return moneyList;
    }
}

Scenario B: Encapsulation ✅ | Information Hiding ✅ Here, we hide the fact that we use an ArrayList. The client only knows they can get a total or an iterator.

public class Wallet {
    private List<Cash> moneyList; 

    // INFORMATION HIDING:
    // The client doesn't know (or care) if we store money in a List, 
    // a Map, or a Database. They just ask for the balance.
    public double getBalance() {
        double total = 0;
        for (Cash c : moneyList) total += c.getValue();
        return total;
    }
    
    // If they really need the items, return a COPY or an Immutable interface
    // so they can't mess with our internals.
    public List<Cash> getHistory() {
        return Collections.unmodifiableList(moneyList);
    }
}

Summary for your script:



Relation Between Objects