Object-Oriented Programming (OOP) in Java

Master the core principles of OOP that make Java powerful, reusable, and easy to maintain

What is Object-Oriented Programming?

Object-Oriented Programming (OOP) is a programming style that organizes code around "objects" rather than functions and logic. Think of objects as real-world things—like a car, student, or phone—each having properties (data) and behaviors (methods).

Java is built on OOP principles, making it easier to create modular, flexible, and scalable applications.

Real-World Analogy: Imagine a "Car" object. It has properties like color, brand, and speed. It also has behaviors like start(), stop(), and accelerate(). OOP lets you model this in code!

The Four Pillars of OOP

1. Encapsulation

Encapsulation means wrapping data (variables) and code (methods) together in a single unit called a class. It hides internal details and protects data from unauthorized access.

Key Idea: Keep data private and provide public methods (getters/setters) to access it.

2. Inheritance

Inheritance allows one class to acquire properties and methods from another class. This promotes code reusability and creates a parent-child relationship.

Key Idea: A "Child" class inherits features from a "Parent" class, like how a student inherits characteristics from a person.

3. Polymorphism

Polymorphism means "many forms." It allows one method or object to behave differently based on the context. You can have the same method name doing different things in different classes.

Key Idea: One interface, multiple implementations—like how a "draw()" method can draw a circle, square, or triangle.

4. Abstraction

Abstraction means hiding complex implementation details and showing only essential features. It focuses on "what" an object does rather than "how" it does it.

Key Idea: You drive a car without knowing how the engine works internally—abstraction hides complexity.

Classes and Objects

A Class is a blueprint or template for creating objects. An Object is an instance of a class—a real entity with actual values.

Example: Creating a Simple Class and Object

// Define a class
class Student {
    String name;
    int age;
    
    void study() {
        System.out.println(name + " is studying.");
    }
}

// Create and use objects
public class Main {
    public static void main(String[] args) {
        Student s1 = new Student();
        s1.name = "Alice";
        s1.age = 20;
        s1.study();
        
        Student s2 = new Student();
        s2.name = "Bob";
        s2.age = 22;
        s2.study();
    }
}
Output:
Alice is studying.
Bob is studying.

Explanation:

  • Student is a class with two properties (name, age) and one method (study)
  • s1 and s2 are objects created from the Student class
  • Each object has its own set of values but shares the same structure

Encapsulation in Action

Let's protect student data using private variables and public getter/setter methods.

Example: Encapsulation with Getters and Setters

class Student {
    private String name;
    private int age;
    
    // Getter for name
    public String getName() {
        return name;
    }
    
    // Setter for name
    public void setName(String name) {
        this.name = name;
    }
    
    // Getter for age
    public int getAge() {
        return age;
    }
    
    // Setter for age with validation
    public void setAge(int age) {
        if (age > 0 && age < 100) {
            this.age = age;
        } else {
            System.out.println("Invalid age!");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("Charlie");
        s.setAge(21);
        
        System.out.println("Name: " + s.getName());
        System.out.println("Age: " + s.getAge());
    }
}
Output:
Name: Charlie
Age: 21

Explanation:

  • Variables are private—cannot be accessed directly from outside
  • Public getter and setter methods control access to the data
  • Setter validates age before setting it, protecting data integrity

Inheritance Example

Inheritance allows a child class to reuse code from a parent class, reducing redundancy.

Example: Student Inherits from Person

// Parent class
class Person {
    String name;
    int age;
    
    void displayInfo() {
        System.out.println("Name: " + name + ", Age: " + age);
    }
}

// Child class inherits from Person
class Student extends Person {
    String studentId;
    
    void study() {
        System.out.println(name + " is studying.");
    }
}

public class Main {
    public static void main(String[] args) {
        Student s = new Student();
        s.name = "Diana";
        s.age = 19;
        s.studentId = "S12345";
        
        s.displayInfo();  // Inherited from Person
        s.study();        // Defined in Student
    }
}
Output:
Name: Diana, Age: 19
Diana is studying.

Explanation:

  • Student inherits name, age, and displayInfo() from Person
  • Student adds its own property (studentId) and method (study)
  • Code reusability: no need to rewrite common properties in Student

Polymorphism Example

Polymorphism allows methods with the same name to behave differently in different classes.

Example: Method Overriding

class Animal {
    void sound() {
        System.out.println("Animal makes a sound");
    }
}

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

class Cat extends Animal {
    void sound() {
        System.out.println("Cat meows");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal a1 = new Dog();
        Animal a2 = new Cat();
        
        a1.sound();  // Calls Dog's sound()
        a2.sound();  // Calls Cat's sound()
    }
}
Output:
Dog barks
Cat meows

Explanation:

  • Both Dog and Cat override the sound() method from Animal
  • Same method name, different behavior—that's polymorphism
  • The actual method called depends on the object type at runtime

Why Use OOP?

  • Code Reusability: Write once, use multiple times through inheritance
  • Modularity: Break complex programs into smaller, manageable classes
  • Security: Encapsulation protects data from unauthorized access
  • Flexibility: Polymorphism makes code more flexible and extensible
  • Easy Maintenance: Changes in one class don't affect others

Remember: OOP is like building with LEGO blocks—each piece (class) is self-contained, reusable, and can connect with others to build something bigger!