Definition
The key differences:
- Static variable: One shared copy stored with the class (Metaspace). Accessed via
ClassName.field. Created when the class loads, lives until the class is unloaded. - Instance variable: Separate copy for each object, stored on the heap inside the object. Accessed via
objectRef.field. Created withnew, lives until the object is garbage collected.
The bank's base interest rate (static) is one number on the head-office notice board. Every branch reads the same number. A customer's balance (instance) is printed in each customer's own passbook. Changing the interest rate affects every customer. Changing one customer's balance affects only that customer.
Understanding the Concepts
Side-by-side comparison
The most effective way to understand the difference is to see both types in the same class. A static variable has one copy shared across all instances. An instance variable has a separate copy inside each object.
package com.bank.core;
import java.math.BigDecimal;
public class Account {
private static double baseRate = 4.0; // one copy for the class
private BigDecimal balance; // one copy per object
public Account(BigDecimal balance) {
this.balance = balance;
}
public static void setBaseRate(double rate) {
baseRate = rate; // changes for ALL accounts
}
public BigDecimal getInterest() {
return balance.multiply(BigDecimal.valueOf(baseRate / 100));
}
}
Account a = new Account(new BigDecimal("500000"));
Account b = new Account(new BigDecimal("200000"));
System.out.println(a.getInterest()); // 20000.0 (500000 * 4%)
System.out.println(b.getInterest()); // 8000.0 (200000 * 4%)
Account.setBaseRate(5.0); // changes for ALL accounts
System.out.println(a.getInterest()); // 25000.0 (500000 * 5%)
System.out.println(b.getInterest()); // 10000.0 (200000 * 5%)
Changing baseRate affects every Account object. Changing balance on one object affects only that object.
Full comparison table
| Property | Static variable | Instance variable |
|---|---|---|
| Copies | One per class | One per object |
| Stored in | Metaspace (class data) | Heap (inside the object) |
| Accessed via | ClassName.field | objectRef.field or this.field |
| Created when | Class is loaded | Object is created (new) |
| Destroyed when | Class is unloaded | Object is garbage collected |
| Default value | Same as instance (0, null, false) | 0, null, false |
| Thread safety | Shared: needs synchronization | Per-object: shared only if the object is shared |
| Use case | Constants, counters, config | Object state (balance, name, ID) |
What about memory layout?
Account a = new Account(new BigDecimal("500000"));
Account b = new Account(new BigDecimal("200000"));
Metaspace (class data):
Account.baseRate = 4.0 ← one shared copy
Heap:
Account a: Account b:
┌────────────────┐ ┌────────────────┐
│ balance: 500000│ │ balance: 200000│ ← separate copies
└────────────────┘ └────────────────┘
How is this relevant to banking?
In a banking application, the distinction maps naturally to shared configuration versus per-customer data.
package com.bank.core;
import java.math.BigDecimal;
import java.util.concurrent.atomic.AtomicInteger;
public class SavingsAccount {
// Static: shared across all savings accounts
private static BigDecimal minimumBalance = new BigDecimal("10000.00");
private static final AtomicInteger accountCount = new AtomicInteger(0);
// Instance: unique to each account
private final String accountId;
private BigDecimal balance;
public SavingsAccount(String accountId, BigDecimal initialDeposit) {
this.accountId = accountId;
this.balance = initialDeposit;
accountCount.incrementAndGet(); // shared counter, needs thread safety
}
public static int getTotalAccounts() {
return accountCount.get();
}
public boolean meetsMinimum() {
return balance.compareTo(minimumBalance) >= 0;
}
}
minimumBalance is static because it is the same policy for every savings account. balance is instance because each customer has their own. accountCount is static because it tracks the total across all accounts.
What are common mistakes?
- Using a static field for per-object state. If you make
balancestatic, all accounts share one balance – deposits by one customer change everyone's balance. - Accessing static fields via instance references.
account.baseRatecompiles but is misleading. UseAccount.baseRateso the reader knows it is a class-level field. - Not synchronizing mutable statics. Multiple threads incrementing a
static int countercause lost updates. UseAtomicIntegerorsynchronized.
What should a senior engineer know?
- Constants should be
static final.private static final BigDecimal MINIMUM_BALANCE = new BigDecimal("10000.00");is the standard pattern. - Static fields survive object GC. Even if all Account objects are collected,
Account.baseRatepersists until the classloader is collected. - AtomicInteger for thread-safe static counters.
private static final AtomicInteger count = new AtomicInteger(0);is safe without synchronized. - Static fields and testing. Global mutable state makes unit tests harder because tests can interfere with each other. Prefer dependency injection over static state for testability.
Visual Overview
static variable (baseRate = 4.0): instance variable (balance):
one copy in Metaspace one copy per object on heap
shared by ALL instances private to each object
changed via ClassName.field changed via this.field
lives until class unloaded lives until object GC'd
Account.setBaseRate(5.0) → ALL accounts see 5.0
a.balance = 500000 → only 'a' has 500000
Key Takeaway
A static variable has one copy shared by all instances, stored with the class in Metaspace. An instance variable has a separate copy per object, stored on the heap inside each object. Changing a static variable affects every instance. Changing an instance variable affects only that object.
In banking, the base interest rate is static because it is one value for the whole bank. A customer's balance is an instance variable because each customer has their own. Constants are static final. Mutable static counters need thread synchronization.
One sentence to remember: static is one copy for the class, instance is one copy per object.
---