System Design
1. System Prerequisites

Classes, Objects & Instances

⏱ 0s active on this topic

In simple words

A class is a blueprint — a description of what something has and what it can do, like an architect's drawing of a house. An object is a real thing built from that blueprint, like an actual house standing on a street. One blueprint can build as many objects as you like; they all have the same shape, but each one has its own values. Instance is just another word for an object — account1 is an instance of the class BankAccount.


What is a class?

A class is a blueprint that defines the structure and behaviour that all objects of that type will have. It defines what data (fields) and what actions (methods) the object will have.

A class itself does nothing — it's just a definition. No memory is allocated for a class until an object is created from it.

// This is a CLASS — just a blueprint, nothing is created yet
class BankAccount {
    // Fields — what data every BankAccount object will hold
    private String accountId;
    private String ownerId;
    private double balance;

    // Constructor — how to create a BankAccount object
    public BankAccount(String accountId, String ownerId, double initialBalance) {
        this.accountId = accountId;
        this.ownerId = ownerId;
        this.balance = initialBalance;
    }

    // Methods — what actions every BankAccount object can do
    public void credit(double amount) {
        if (amount <= 0) throw new IllegalArgumentException("Amount must be positive");
        this.balance += amount;
    }

    public void debit(double amount) {
        if (amount > this.balance) throw new IllegalStateException("Insufficient balance");
        this.balance -= amount;
    }

    public double getBalance() {
        return this.balance;
    }
}

What is an object?

An object is a concrete instance of a class — created in memory using the new keyword. Each object has its own copy of the fields defined in the class.

// Creating OBJECTS from the BankAccount class
// Each object is independent — its own data, its own memory
BankAccount account1 = new BankAccount("ACC001", "user_alice", 5000.00);
BankAccount account2 = new BankAccount("ACC002", "user_bob",   2000.00);
BankAccount account3 = new BankAccount("ACC003", "user_carol", 10000.00);

// Each object has its own state
account1.debit(1000);
System.out.println(account1.getBalance());  // 4000.00 — only account1 changed
System.out.println(account2.getBalance());  // 2000.00 — account2 unaffected
Class (blueprint):          Objects (created from blueprint):
+-----------------+         +----------------------------+
|  BankAccount    |  --->   | account1: ACC001, 5000.00  |
|  - accountId    |         +----------------------------+
|  - ownerId      |  --->   | account2: ACC002, 2000.00  |
|  - balance      |         +----------------------------+
|  + credit()     |  --->   | account3: ACC003, 10000.00 |
|  + debit()      |         +----------------------------+
+-----------------+         Each has its own field values.
                            All share the same methods.

Try it — build objects from one class and see that they don't affect each other:

class
BankAccount
accountIdbalance
credit() · debit()
static instanceCount = 0
one value for the whole class, not per object
No objects yet — click “new BankAccount(…)”.

Each object keeps its own balance — debiting one leaves the others untouched (that’s an instance field). instanceCount is static: a single value shared by the whole class.


What is an instance?

Instance and object mean the same thing.

account1 is an instance of BankAccount
account2 is an instance of BankAccount
account3 is an instance of BankAccount

"creating an object" = "instantiating a class"

The only subtle difference in usage:

  • "Object" emphasises the thing in memory
  • "Instance" emphasises the relationship to the class it came from

In interviews and real conversations, they are used interchangeably.


Instance variables vs class (static) variables

TypeBelongs toOne copy perAccess
Instance variable (field)Each objectEach objectobject.field
Static variableThe classEntire class (per JVM)ClassName.field
class UserSession {
    // INSTANCE variable — each session object has its own sessionId
    private String sessionId;
    private String userId;
    private long expiresAt;

    // STATIC variable — shared across ALL UserSession objects
    private static int activeSessions = 0;          // counts all active sessions
    private static final int MAX_SESSIONS = 10000;  // constant

    public UserSession(String userId) {
        this.sessionId = UUID.randomUUID().toString();
        this.userId = userId;
        this.expiresAt = System.currentTimeMillis() + 3600000;
        activeSessions++;   // increment shared counter
    }

    public void invalidate() {
        activeSessions--;   // decrement when session ends
    }

    public static int getActiveSessions() {
        return activeSessions;
    }
}

UserSession s1 = new UserSession("user_alice");
UserSession s2 = new UserSession("user_bob");

System.out.println(UserSession.getActiveSessions());  // 2 — accessed via class name
System.out.println(s1.sessionId);  // unique to s1
System.out.println(s2.sessionId);  // different value, unique to s2

Instance methods vs static methods

class MathUtils {
    // STATIC method — no object needed, operates on parameters only
    public static int add(int a, int b) {
        return a + b;
    }
}

int result = MathUtils.add(3, 5);   // called on the CLASS, no object created

class Counter {
    private int count = 0;   // instance variable

    // INSTANCE method — operates on this object's state
    public void increment() { count++; }
    public int getCount() { return count; }
}

Counter pageCounter = new Counter();
Counter loginCounter = new Counter();
pageCounter.increment();
pageCounter.increment();   // pageCounter.count = 2
loginCounter.increment();  // loginCounter.count = 1  (independent)

Object lifecycle

1. Declaration     ->  BankAccount account;              (reference variable, no object yet)
2. Instantiation   ->  account = new BankAccount(...)    (object created in heap memory)
3. Initialisation  ->  constructor runs, fields set
4. Usage           ->  account.credit(500)
5. Garbage collected -> when no references point to it (the JVM handles this)

Memory — where objects live

Stack Memory                     Heap Memory
------------                     -----------
account1  --------------------->  { accountId:"ACC001", balance: 5000 }
account2  --------------------->  { accountId:"ACC002", balance: 2000 }
account3  --------------------->  { accountId:"ACC003", balance: 10000 }
  • Stack: holds reference variables (the pointers)
  • Heap: holds the actual object data
  • Multiple references can point to the same object:
BankAccount acc = new BankAccount("ACC001", "alice", 5000);
BankAccount alias = acc;        // both point to the SAME object in the heap

alias.debit(1000);
System.out.println(acc.getBalance());  // 4000 — same object changed

Where this shows up in system design

Every service you draw is a class. When you say "Order Service" in an interview, this is literally what you mean:

class OrderService {
    private OrderRepository orderRepo;              // dependencies (other classes)
    private InventoryService inventoryService;
    private NotificationService notificationService;

    public Order placeOrder(OrderRequest request) { ... }   // core behaviour
    public Order getOrder(String orderId) { ... }
    public void cancelOrder(String orderId) { ... }
}

Entities / domain models are classes — UserService manages User objects, PaymentService manages Payment and Transaction objects.

Spring beans are singleton objects — Spring creates one instance of a @Service class and shares it across every request. That one instance must be stateless or thread-safe (which is why we inject repositories and don't store mutable state in service fields).


Senior-level nuances (these are what actually get tested)

Nobody asks "what is a class" at 10 years' experience. They ask things downstream of it:

1. Identity vs equality. == compares references — is it literally the same object on the heap. .equals() compares meaning. Override equals() and hashCode() together, on the same fields, ideally an immutable business key (orderId) — never a mutable field. If an object goes into a HashSet or is used as a Map key and you skip one of the two, you get silent bugs (duplicates stored, contains() misses).

2. Value vs reference semantics. Passing an object passes the reference. A method can mutate your object. Defend with a defensive copy on the way in/out, or make the object immutable.

3. Immutability. An immutable object (all fields final, set in the constructor, no setters) is automatically thread-safe and safe to share and cache. Default domain models and DTOs to immutable; make things mutable only when you have a reason.

4. static is not a free global. activeSessions++ is read-modify-write and not thread-safe — needs AtomicInteger. And static is per-JVM, so with 4 server instances there are 4 separate counters — it is not a global count. A real global counter needs a shared store (Redis) or a metrics system. Static mutable state also leaks between unit tests.


In the interview — the one-liner

"A class is the blueprint — fields and methods. An object is a concrete instance on the heap, created with new; each object has its own instance fields but shares static fields across the whole class per JVM. In practice the thing that bites you is a singleton service holding mutable instance state across request threads, or a domain object used as a map key without equals / hashCode — so I keep services stateless and domain models immutable."


Quick revision — 6 lines

  1. Class = blueprint. Object / instance = a thing built from the blueprint.
  2. Each object has its own instance variables; static variables are shared across all objects (per JVM).
  3. Instance methods need an object; static methods belong to the class.
  4. Objects live on the heap; references live on the stack. Two references can point to one object.
  5. In Spring, service beans are singleton objects — must be stateless or thread-safe.
  6. What gets tested: identity vs equality (== vs equals/hashCode), reference semantics, immutability, static not being thread-safe or global.

Quick-revision quiz

Question 1 of 18
A Spring @Service (one shared instance) has a field `private double lastTotal;` updated on every request. Two requests hit it at the same time. What is the core problem?