OOP in Java

·

9 min read

Java is one of the most popular programming languages, and its power lies in its Object-Oriented Programming (OOP) model. OOP makes code reusable, scalable, and easier to maintain by structuring it around objects rather than functions. This blog will cover all essential OOP concepts in Java briefly, with real-world use cases and code snippets for reference.

1. Classes and Objects

Theory

A class is a blueprint or template for creating objects. It defines the properties (fields) and behaviors (methods) that objects of the class will have. An object, on the other hand, is an instance of a class that holds real data in memory.

Use Case

Consider a banking application where an Account class defines properties like balance and accountNumber, while the objects represent actual customer accounts.

Code:

class Account {
    int accountNumber;
    double balance;

    void deposit(double amount) {
        balance += amount;
    }

    void withdraw(double amount) {
        if (amount <= balance) {
            balance -= amount;
        } else {
            System.out.println("Insufficient balance!");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Account acc1 = new Account();
        acc1.accountNumber = 12345;
        acc1.deposit(5000);
        acc1.withdraw(2000);
    }
}

2. Constructors

Theory

A constructor is a special method that initializes an object when it is created. It has the same name as the class and does not have a return type.

Use Case

Useful for setting initial values for objects, like assigning default account balance in a banking system.

Code:

class Account {
    int accountNumber;
    double balance;

    Account(){
    // Deafult constructor
    }

    Account(int accNum, double initialBalance) {
        this.accountNumber = accNum;
        this.balance = initialBalance;
    }
}

public class Main {
    public static void main(String[] args) {
        Account acc1 = new Account(12345, 5000);
        System.out.println("Account Created with Balance: " + acc1.balance);
    }
}

3. Static Keyword

Theory

The static keyword in Java is used for memory management. A static variable or method belongs to the class rather than any specific object.

Use Case

We can call the static functions without creating an object of the respective class.

Code:

class Bank {
    static double interestRate = 5.5;
}

public class Main {
    public static void main(String[] args) {
        System.out.println("Interest Rate: " + Bank.interestRate);
    }
}

4. Singleton Class

Theory

A singleton class ensures that only one instance of the class is created and shared.

Code:

class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

public class Main {
    public static void main(String[] args) {
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();
        System.out.println(obj1 == obj2); // true
    }
}

5. Inheritance

Theory

Inheritance allows one class to acquire the properties and behaviors of another class. The parent class (superclass) provides common functionalities, while the child class (subclass) extends it, adding or modifying features.

Types of Inheritance:

We don’t have Multiple Inheritance in Java as we need to implement Interfaces for that.

Use Case

Commonly used in hierarchical relationships like Animal → Pets→ Dog, where all pets share some traits but dogs have specific characteristics.

Code:

class Animal {
    void eat() {
        System.out.println("This animal eats food");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println("Dog barks");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.eat(); // Inherited from Animal
        d.bark();
    }
}

6. Interfaces

Theory

An interface in Java defines a contract that implementing classes must follow. Unlike abstract classes, interfaces cannot contain concrete methods.

Use Case

Used in frameworks and APIs, such as Java’s Collection Framework, where List, Set, and Queue implement the Collection interface.

Code:

interface Animal {
    void makeSound();
}

class Cat implements Animal {
    public void makeSound() {
        System.out.println("Meow");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myCat = new Cat();
        myCat.makeSound();
    }
}

7. Polymorphism

Theory

Polymorphism allows objects to take multiple forms. It is categorized into two types:

  • Compile-time Polymorphism (Method Overloading)

  • Runtime Polymorphism (Method Overriding)

Use Case

Polymorphism is useful when different classes share the same method but behave differently, such as different shapes having their own implementation of area().

Code:

// Compile-time Polymorphism (Method Overloading)
class Shape {
    void draw() {
        System.out.println("Drawing a shape");
    }

    void draw(String color) { // Overloaded method
        System.out.println("Drawing a shape in " + color);
    }
}

// Runtime Polymorphism (Method Overriding)
class Circle extends Shape {
    void draw() {
        System.out.println("Drawing a Circle");
    }
}

class Rectangle extends Shape {
    void draw() {
        System.out.println("Drawing a Rectangle");
    }
}

class Triangle extends Shape {
    void draw() {
        System.out.println("Drawing a Triangle");
    }
}

public class Main {
    public static void main(String[] args) {
        // Compile-time polymorphism (Method Overloading)
        Shape shape = new Shape();
        shape.draw();
        shape.draw("Red");

        System.out.println("---------------------");

        // Runtime polymorphism (Method Overriding)
        Shape s1 = new Circle();
        Shape s2 = new Rectangle();
        Shape s3 = new Triangle();

        s1.draw(); // Drawing a Circle
        s2.draw(); // Drawing a Rectangle
        s3.draw(); // Drawing a Triangle
    }
}

8. Access Modifiers

Theory

Access modifiers control the visibility of class members. The four types are:

  • private → Accessible within the same class.

  • default → Accessible within the same package.

  • protected → Accessible within the same package and subclasses.

  • public → Accessible everywhere.

Use Case

Used for maintaining security and preventing unauthorized access to critical data.

9. Encapsulation

Theory

Encapsulation is the practice of restricting direct access to data fields and only allowing modifications through methods that ensure data integrity.

Use Case

Used in real-world applications like banking, where private fields such as balance should only be modified using methods like deposit() and withdraw().

Code:

class BankAccount {
    private double balance;

    // Getter method to access balance
    public double getBalance() {
        return balance;
    }

    // Setter method to modify balance safely
    public void setBalance(double balance) {
        if (balance >= 0) {
            this.balance = balance;
        } else {
            System.out.println("Balance cannot be negative!");
        }
    }

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        } else {
            System.out.println("Deposit amount must be positive!");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount();

        // Using setter to initialize balance
        acc.setBalance(1000); 

        // Depositing money
        acc.deposit(5000);

        // Getting balance using getter
        System.out.println("Balance: " + acc.getBalance());
    }
}

10. Abstraction

Theory

Abstraction hides implementation details from the user, exposing only essential features. It is achieved using abstract classes.

Use Case

ATM machines provide a simple interface for users without exposing internal mechanisms like cash withdrawal processing.

Code:

abstract class Vehicle {
    abstract void start(); // Abstract method
}

class Car extends Vehicle {
    void start() {
        System.out.println("Car starts with a key");
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle myCar = new Car();
        myCar.start();
    }
}

11. Object Class

Theory

All Java classes are inherited from the Object class, which provides methods like toString(), equals(), and hashCode().

12. Annotations

Theory

Annotations provide metadata about code, helping tools like compilers and frameworks process it correctly.

Use Case

Used for marking methods as deprecated, overriding methods.

Code:

class Parent {
    void show() {
        System.out.println("Parent class");
    }
}

class Child extends Parent {
    @Override
    void show() {
        System.out.println("Child class");
    }
}

13. Collection Framework in Java

Theory

The Java Collection Framework (JCF) is a unified architecture that provides ready-to-use data structures and algorithms to store, manipulate, and retrieve data efficiently. It contains multiple interfaces (like List, Set, Map, Queue) and concrete implementations (like ArrayList, HashSet, HashMap, etc.).

This framework is part of java.util package and helps developers avoid reinventing the wheel by providing optimized implementations of commonly used data structures.

Key Interfaces in Collection Framework

  1. List Interface – Ordered collection (allows duplicates)

  2. Set Interface – Unordered collection (no duplicates)

  3. Queue Interface – Follows FIFO (First In, First Out)

  4. Map Interface – Stores key-value pairs

1. List Interface (Ordered Collection, Allows Duplicates)

The List interface allows storing ordered elements with duplicate values and provides positional access.

Implementations:

  • ArrayList – Resizable array, fast read, slow insert/remove

  • LinkedList – Doubly linked list, fast insert/remove, slow read

  • Vector – Thread-safe version of ArrayList

Example: ArrayList

javaCopyEditimport java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> names = new ArrayList<>();
        names.add("Alice");
        names.add("Bob");
        names.add("Alice"); // Duplicates are allowed

        System.out.println(names); // [Alice, Bob, Alice]
    }
}

2. Set Interface (Unique Elements, No Duplicates)

The Set interface ensures only unique elements are stored.

Implementations:

  • HashSet – Uses hashing (fastest, no order)

  • LinkedHashSet – Maintains insertion order

  • TreeSet – Stores elements in sorted order

Example: HashSet

javaCopyEditimport java.util.HashSet;

public class Main {
    public static void main(String[] args) {
        HashSet<Integer> numbers = new HashSet<>();
        numbers.add(10);
        numbers.add(20);
        numbers.add(10); // Duplicate, won't be added

        System.out.println(numbers); // [10, 20]
    }
}

3. Queue Interface (FIFO – First In, First Out)

Queues, like a task scheduler, are useful when processing elements in sequential order.

Implementations:

  • LinkedList (as a queue) – Doubly linked list

  • PriorityQueue – Orders elements based on priority

Example: PriorityQueue

javaCopyEditimport java.util.PriorityQueue;

public class Main {
    public static void main(String[] args) {
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        pq.add(30);
        pq.add(10);
        pq.add(20);

        System.out.println(pq.poll()); // 10 (smallest first)
    }
}

4. Map Interface (Key-Value Pairs)

Map stores data in key-value pairs.

Implementations:

  • HashMap – Unordered, allows null keys

  • LinkedHashMap – Maintains insertion order

  • TreeMapSorted by keys

Example: HashMap

javaCopyEditimport java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<String, Integer> studentMarks = new HashMap<>();
        studentMarks.put("Alice", 95);
        studentMarks.put("Bob", 88);

        System.out.println(studentMarks.get("Alice")); // 95
    }
}

Additional Concepts in Collection Framework

Iterable & Iterator (Traversing Collections)

Every collection implements Iterable, which allows looping using an Iterator.

Example: Iterating a List Using Iterator

javaCopyEditimport java.util.ArrayList;
import java.util.Iterator;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");

        Iterator<String> it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

When to Use Which Collection?

Collection TypeBest Use Case
ArrayListFast random access, dynamic arrays
LinkedListFast insertions/deletions
HashSetUnordered unique elements
TreeSetSorted unique elements
HashMapKey-value pairs, fast lookup
PriorityQueueElements processed by priority

Summary

  • Java's Collection Framework provides efficient data structures for different needs.

  • List (Ordered, allows duplicates) → Use ArrayList, LinkedList.

  • Set (Unique elements) → Use HashSet, TreeSet.

  • Queue (FIFO) → Use LinkedList, PriorityQueue.

  • Map (Key-Value) → Use HashMap, TreeMap.

14. Vector Class

Theory

Vector is a synchronized, resizable array implementation in Java.

Use Case

Used in multi-threaded environments where thread safety is required.

Code:

import java.util.Vector;

public class Main {
    public static void main(String[] args) {
        Vector<Integer> numbers = new Vector<>();
        numbers.add(10);
        numbers.add(20);
        System.out.println(numbers);
    }
}

15. Enums

Theory

Enums define a set of named constants, improving code readability and reducing errors.

Use Case

Used for defining predefined values like days of the week or status codes.

Code:

enum Day { MONDAY, TUESDAY, WEDNESDAY }

public class Main {
    public static void main(String[] args) {
        Day today = Day.MONDAY;
        System.out.println("Today is " + today);
    }
}

Conclusion

Object-oriented programming in Java provides powerful tools for designing robust applications. Mastering these concepts will help you write clean, scalable, and efficient Java code as I’m practicing It while building Android apps. Keep practicing and applying these concepts in real-world projects!