Skip to content
Dev Dump

OOP Concepts

Object-Oriented Programming (OOP) is a programming paradigm that organizes code around objects rather than functions and logic. These objects bundle data (attributes) and behavior (methods) together, making code more modular, reusable, and easier to maintain.


A class is a blueprint; an object is an instance of that blueprint.

A class defines the structure (attributes) and behavior (methods) that its objects will have. You can create multiple objects from a single class, each with its own state.

Classes and Objects A class is like a blueprint; objects are the actual houses built from it.

// Class: The Blueprint
class Car {
String brand;
String color;
int speed;
void accelerate() {
speed += 10;
System.out.println(brand + " accelerating to " + speed + " km/h");
}
}
// Objects: Instances of the Blueprint
Car car1 = new Car();
car1.brand = "Toyota";
car1.color = "Red";
Car car2 = new Car();
car2.brand = "Honda";
car2.color = "Blue";
car1.accelerate(); // Toyota accelerating to 10 km/h
car2.accelerate(); // Honda accelerating to 10 km/h

Encapsulation bundles data and methods together, hiding internal state and requiring all interaction through well-defined interfaces.

Think of it as a protective capsule: the internal workings are hidden, and access is controlled through public methods (getters/setters).

Encapsulation Private data is protected; access is only through controlled public methods.

class BankAccount {
private double balance; // Hidden from outside
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
}
}
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
public double getBalance() {
return balance; // Controlled read access
}
}
// Usage
BankAccount account = new BankAccount(1000);
account.deposit(500);
// account.balance = -9999; // ERROR: balance is private!
System.out.println(account.getBalance()); // 1500

Abstraction hides complex implementation details and exposes only the essential features.

Like a car dashboard: you see the speedometer and steering wheel, not the engine internals. Users interact with a simple interface without needing to understand the complexity underneath.

Abstraction Simple interface hides the complex machinery beneath.

// Abstract interface - what users see
interface EmailService {
void sendEmail(String to, String subject, String body);
}
// Complex implementation - hidden from users
class SmtpEmailService implements EmailService {
private void connectToServer() { /* SMTP handshake */ }
private void authenticate() { /* Login credentials */ }
private void formatMessage() { /* MIME encoding */ }
private void handleRetry() { /* Retry logic */ }
@Override
public void sendEmail(String to, String subject, String body) {
connectToServer();
authenticate();
formatMessage();
// ... complex SMTP protocol
System.out.println("Email sent to " + to);
}
}
// Usage - simple!
EmailService email = new SmtpEmailService();
email.sendEmail("user@example.com", "Hello", "Welcome!");

Inheritance allows a child class to inherit attributes and methods from a parent class, promoting code reuse.

The child class (subclass) gets all the functionality of the parent class (superclass) and can add or override behavior.

Inheritance Child classes inherit from and extend the parent class.

// Parent Class
class Vehicle {
String brand;
int speed;
void start() {
System.out.println(brand + " starting...");
}
void accelerate() {
speed += 10;
}
}
// Child Class - inherits from Vehicle
class Car extends Vehicle {
int doors;
void openTrunk() {
System.out.println("Trunk opened");
}
}
// Another Child Class
class Motorcycle extends Vehicle {
boolean hasSidecar;
void wheelie() {
System.out.println("Doing a wheelie!");
}
}
// Usage
Car car = new Car();
car.brand = "Toyota";
car.start(); // Inherited method
car.accelerate(); // Inherited method
car.openTrunk(); // Car-specific method

Polymorphism means “many forms” — the same interface can have different implementations.

A single method name (draw()) behaves differently depending on which object calls it. This enables flexible, extensible code.

Polymorphism Same method call, different behaviors based on the actual object type.

// Common Interface
interface Shape {
void draw();
double area();
}
// Different Implementations
class Circle implements Shape {
private double radius;
public Circle(double radius) { this.radius = radius; }
@Override
public void draw() { System.out.println("Drawing a circle"); }
@Override
public double area() { return Math.PI * radius * radius; }
}
class Rectangle implements Shape {
private double width, height;
public Rectangle(double w, double h) { width = w; height = h; }
@Override
public void draw() { System.out.println("Drawing a rectangle"); }
@Override
public double area() { return width * height; }
}
// Polymorphic Usage
Shape[] shapes = { new Circle(5), new Rectangle(4, 6) };
for (Shape shape : shapes) {
shape.draw(); // Calls the correct implementation!
System.out.println("Area: " + shape.area());
}
// Output:
// Drawing a circle
// Area: 78.54
// Drawing a rectangle
// Area: 24.0

A constructor is a special method that initializes an object when it’s created.

Constructors have the same name as the class and no return type. They set up the initial state of an object.

Constructors Constructors initialize object state at creation time.

class Person {
String name;
int age;
// Default Constructor
public Person() {
this.name = "Unknown";
this.age = 0;
}
// Parameterized Constructor
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Constructor Chaining
public Person(String name) {
this(name, 18); // Calls the parameterized constructor
}
}
// Usage
Person p1 = new Person(); // Unknown, 0
Person p2 = new Person("Alice", 25); // Alice, 25
Person p3 = new Person("Bob"); // Bob, 18 (default age)

Access modifiers control the visibility of classes, methods, and fields.

Java has four access levels, from most restrictive to most open:

Access Modifiers Access modifiers define visibility boundaries.

ModifierSame ClassSame PackageSubclassWorld
private
default (no modifier)
protected
public
class Example {
private int privateField; // Only this class
int defaultField; // Same package only
protected int protectedField; // Same package + subclasses
public int publicField; // Accessible everywhere
private void privateMethod() { }
void defaultMethod() { }
protected void protectedMethod() { }
public void publicMethod() { }
}

Static members belong to the class itself; instance members belong to individual objects.

Static members are shared across all instances, while instance members are unique to each object.

Static vs Instance Static members are shared; instance members are unique per object.

class Counter {
// Static: shared across ALL instances
private static int totalCount = 0;
// Instance: unique to EACH object
private int id;
public Counter() {
totalCount++; // Increment shared counter
this.id = totalCount; // Assign unique ID
}
public static int getTotalCount() {
return totalCount; // Access static member
}
public int getId() {
return id; // Access instance member
}
}
// Usage
Counter c1 = new Counter(); // id=1, totalCount=1
Counter c2 = new Counter(); // id=2, totalCount=2
Counter c3 = new Counter(); // id=3, totalCount=3
System.out.println(c1.getId()); // 1 (instance)
System.out.println(c2.getId()); // 2 (instance)
System.out.println(Counter.getTotalCount()); // 3 (static, shared)
AspectStaticInstance
Belongs toClassObject
MemoryOne copyOne per object
AccessClassName.memberobject.member
Use caseShared data, utility methodsObject-specific state