One interest rate, a thousand accounts
Riya's mini-bank project has an Account class with a balance and a rate field. When the bank changes its rate from 7% to 6.5%, she has to update every single account object, and she misses one.
Sir, every account has its own copy of the rate. When the rate changes, I have to loop over all of them.
Does the rate belong to Riya's account or Kabir's account?
Neither. It belongs to the bank… to accounts in general.
Then make it static double rate. A static field belongs to the class: there is exactly one copy, shared by every object. Change it once with Account.rate = 6.5 and every account sees the new rate immediately.
What does static mean?
The static keyword marks a member as belonging to the class itself rather than to its instances. A static variable (class variable) has a single copy shared by all objects of the class, created when the class is initialised. A static method (class method) can be called without creating an object, using ClassName.method(); it has no this reference and cannot directly access instance variables or instance methods. A static block runs once, when the class is initialised. static can also be applied to nested classes and used in import static declarations.
Normal (instance) members: one per object. Static members: one for the whole class. If the value or behaviour doesn't depend on which object you're talking about, it can be static.
Words you'll meet in this lesson
Math.sqrt(16). No object needed, no this.static { … }: runs once when the class is first initialised.Math or Arrays.Instance vs static at a glance
| Instance member | Static member | |
|---|---|---|
| Belongs to | Each object | The class |
| How many copies | One per object | Exactly one |
| Created when | new creates the object | The class is initialised (first use) |
| Accessed as | acc.balance, acc.deposit(…) | Account.rate, Math.max(…) |
Can use this? | Yes | No |
| Typical use | Data that differs per object | Shared settings, counters, constants, helper methods |
Exam tip: “Why is main static?” Because the JVM must call it before any object exists. A static method can be called on the class alone. Also remember: static methods can use static members directly, but need an object reference to use instance members.
Four places you can write static
Static variables
Shared data: an object counter, a shared rate, a cache. Combine with final for constants: static final int MAX_SEATS = 72;
Static methods
Work that needs no object state: Math.max, Integer.parseInt, Arrays.sort, factory methods like List.of.
Static blocks
Setup that runs once when the class loads: filling a lookup table, reading a default setting.
static { … }The fourth, static nested classes, gets its own lesson (10.5). And static imports let you use static members without the class name:
import static java.lang.Math.max;
import static java.lang.Math.PI;
public class Main {
public static void main(String[] args) {
System.out.println(max(12, 30)); // instead of Math.max
System.out.println(PI * 2 * 2); // instead of Math.PI
}
}Static blocks run once, at first use
class Config {
static int gstRate;
static {
System.out.println("Config loading...");
gstRate = 18;
}
}
public class Main {
public static void main(String[] args) {
System.out.println("main starts");
System.out.println(Config.gstRate);
System.out.println(Config.gstRate);
}
}“Config loading...” prints only once, and only when Config is first used, not when the program starts. That's class initialisation, which you'll see in detail in Lesson 8.4.
Static state is shared state. A static field that changes (like a counter) is visible to every part of the program and every thread. That's useful, but it makes code harder to test and needs care with threads (Module 12). Prefer constants (static final) and stateless static methods.
Static and instance members working together
Declare which data is shared
When the class is initialised, the JVM creates storage forclass Account { static double rate = 7.0; // one for all accounts static int count = 0; // how many accounts exist double balance; // one per accountrateandcountonce, with the class. No object exists yet.Update the shared counter in the constructor
EachAccount(double opening) { balance = opening; // this object's field count++; // the class's field }new Account(…)creates a freshbalanceinside the new object, but all of them increment the samecount.Instance methods can read static fields
Inside an instance method there is a current object (double yearlyInterest() { return balance * rate / 100; // own balance, shared rate }this), and the class is always reachable, so both kinds of member are available.Static methods have no current object
A static method runs withoutstatic void setRate(double r) { rate = r; // fine: static field // balance = 0; // error: which account's balance? }this. Writingbalancethere gives non-static variable balance cannot be referenced from a static context. To use an object's fields, pass the object in as a parameter.Call static members through the class name
You can writeAccount.setRate(6.5); System.out.println(Account.count + " accounts at " + Account.rate + "%");a1.rate, but it hides the fact that the value is shared. IDEs warn about it; use the class name.
Three accounts, one shared rate
Left: the code and what it prints. Right: the objects on the heap, each with its own balance, and the single copy of the static fields kept with the class.
- The first time the program uses
Account, the class is loaded and initialised:rate = 7.0andcount = 0are set up. new Account(5000)creates object #1. The constructor sets its balance and increments the sharedcountto 1.- A second object, #2, with its own balance. The same
countbecomes 2. - Interest uses each object's own balance and the one shared rate: 5000 × 7% = 350, 12000 × 7% = 840.
Account.setRate(6.5)changes the single static field. No object was touched.- Both accounts now compute with 6.5%: 325 and 780. Nothing was missed, because there was only one rate to change.
- Static fields are stored with the class, not in any object. In HotSpot they live with the class's
Classobject, created once when the class is initialised. - Object #1 contains only its instance field,
balance. The constructor'scount++updates the class's field. - Object #2 also contains just a balance. There's still exactly one
count: 2. yearlyInterest()readsbalancefrom its own object (this) andratefrom the class.- A static method runs with no object. It can change static fields; touching
balancethere would not compile, because the compiler can't know whose balance you mean. - The next calls read the updated
rate. This is why settings, counters and constants are made static.
static in real projects
Every Java codebase uses static members, mostly for constants and helper methods. Mutable static state is used more carefully.
Watch it with an example: token numbers at a clinic
Every patient gets a Token object with its own number, but one static counter at the reception hands out the numbers, so no two patients get the same one.
- Before anyone arrives: the class has one static field
next = 101. No Token object exists yet. - Asha:
new Token("Asha")creates object #1. The constructor copiesnextinto the object's ownnumberfield, then increments the shared counter to 102. - Ravi: object #2 gets 102; the same counter moves to 103.
- Meena: object #3 gets 103. Each token keeps its own number; the counter is shared.
- The risk: static state can be changed from anywhere. If some code resets
Token.next, numbers repeat. That's why real systems keep counters private and, with many threads, useAtomicInteger(Module 12).
1. Constants for business rules
static final int MAX_SEATS = 72;, static final double GST_RATE = 0.18;. One copy, can't change, readable names instead of magic numbers.
2. Utility classes
Math, Arrays, Collections, Objects and your own DateUtils or GstUtil: groups of static methods that need no object state.
3. Factory methods
List.of(…), Integer.valueOf(…), LocalDate.of(2025, 1, 26). Static methods that create objects, often reusing cached ones.
4. Counters and loggers
A per-class logger (private static final Logger log = …) and simple ID generators. For counters used by many threads at once, real systems use AtomicLong or a database sequence.
Examples are simplified. Large applications avoid mutable static fields for business data, because frameworks may run several copies of the code and tests need fresh state.
Riya's bank with a shared rate
class Account {
static double rate = 7.0;
static int count = 0;
String owner;
double balance;
Account(String owner, double balance) {
this.owner = owner;
this.balance = balance;
count++;
}
double yearlyInterest() {
return balance * rate / 100;
}
static void setRate(double newRate) {
rate = newRate;
}
}
public class Main {
public static void main(String[] args) {
Account a = new Account("Riya", 5000);
Account b = new Account("Kabir", 12000);
System.out.println(Account.count + " accounts at " + Account.rate + "%");
System.out.println(a.owner + ": " + a.yearlyInterest() + ", " + b.owner + ": " + b.yearlyInterest());
Account.setRate(6.5);
System.out.println(a.owner + ": " + a.yearlyInterest() + ", " + b.owner + ": " + b.yearlyInterest());
}
}static double rateOne copy for the class. Every account reads the same value.count++Runs in every constructor call, always on the same shared field.static void setRateCalled on the class:Account.setRate(6.5). It has nothis.Account.countRead through the class name, which makes it obvious the value is shared.
A static counter on the real JVM
This tracer also shows static fields at the top of the heap list. Watch one Token.next serve every object.
Worked examples: real problems, solved and traced in memory
Three common, correct uses of static: a utility method, a constant with a counter, and a shared setting. In each trace, static fields appear at the top of the heap list.
A static GST helper
Problem statement
A billing system needs GST for many prices. The calculation depends only on the price and the rate, not on any object, so write it as a static method in a utility class Gst and call it for two items.
price 1200 at 18%, price 450 at 5%
GST on cover: Rs 216 GST on book: Rs 22
Approach
- Put the logic in
static int amount(int price, int rate). - Call it through the class name:
Gst.amount(…). - No
Gstobject is ever created.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Booking IDs with a fixed prefix
Problem statement
Each booking gets an ID like MP-1001. The prefix is a constant for the whole class and the number comes from a shared counter. Create three bookings and print their IDs.
passengers Asha, Ravi, Meena
MP-1001 Asha MP-1002 Ravi Bookings made: 2
Approach
static final String PREFIX = "MP-"is a constant (final statics aren't shown in the trace: they never change).static int counter = 1000is shared and incremented in the constructor.- Each object stores its own
idString.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Changing a shared minimum balance
Problem statement
A bank's minimum balance applies to every account. Accounts below it pay a fee. Store the minimum as a static field, check two accounts, change the rule once, and check again.
minimum 1000, then 3000; balances 2500 and 800
a pays fee: false, b pays fee: true a pays fee: true, b pays fee: true
Approach
static int minBalanceis shared by all accounts.- An instance method compares this account's balance with the shared minimum.
Account.minBalance = 3000changes the rule for everyone at once.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Check yourself
Quick revision
Lesson 6.4 in one screen
static= belongs to the class. One copy, shared by all objects.- Static fields are created when the class is initialised; instance fields when each object is created.
- Static methods: called as
ClassName.method(), nothis, can't use instance members directly. - Error to remember: non-static variable … cannot be referenced from a static context.
- Static blocks run once, on the class's first use.
import staticdrops the class name. mainis static because the JVM calls it before any object exists.- Use static for constants, helpers and factories; be careful with changing static state.
Interview and viva questions
What is the difference between static and instance variables?
An instance variable belongs to an object; every object has its own copy, created by new. A static variable belongs to the class; there is a single copy shared by all objects, created when the class is initialised. Change a static variable through one object and every object sees the change.
Can we access instance members from a static method?
Not directly, because there is no current object. You can if you have a reference: static void print(Account a) { System.out.println(a.balance); }. That's also how main works with objects: it creates them first.
Can static methods be overridden?
No. A subclass can declare a static method with the same signature, but that hides the parent's method; the call is chosen at compile time from the reference type, not at run time from the object. Overriding (Lesson 7.4) applies only to instance methods.
Where are static variables stored?
With the class rather than in any object. In the HotSpot JVM since Java 8, class metadata is in Metaspace and static fields are stored with the class's java.lang.Class object on the heap. For exams, “in the class area, one copy per class” is the expected answer.
What is a static block used for?
One-time setup for the class: initialising static fields that need several statements, filling lookup tables, or loading a native library. It runs once when the class is initialised, before any static method or field of that class is used.
Practice problems
Decide what should be static and what shouldn't, and practise static methods, blocks and counters. The last three are real business tasks.
Count objects created
Write a class Student with a static counter that increases in the constructor. Create three students and print the count.
Riya, Kabir, Asha
Students: 3
Show solution and explanation
class Student {
static int count = 0;
String name;
Student(String name) {
this.name = name;
count++;
}
}
public class Main {
public static void main(String[] args) {
new Student("Riya");
new Student("Kabir");
new Student("Asha");
System.out.println("Students: " + Student.count);
}
}How it works: each constructor call increments the same field. The objects aren't even stored in variables, yet the count is right.
A static utility method
Write MathUtil.isEven(int n) and MathUtil.square(int n) as static methods and call them without creating an object.
isEven(7), square(12)
false 144
Show solution and explanation
class MathUtil {
static boolean isEven(int n) {
return n % 2 == 0;
}
static int square(int n) {
return n * n;
}
}
public class Main {
public static void main(String[] args) {
System.out.println(MathUtil.isEven(7));
System.out.println(MathUtil.square(12));
}
}How it works: these methods use only their parameters, so there is no reason to require an object. That's the pattern of Math, Arrays and Collections.
Fix the static context error
This doesn't compile: main uses the instance field shop directly. Fix it by creating an object.
shop = "Chai Point"
Chai Point Welcome to Chai Point
Show solution and explanation
public class Main {
String shop = "Chai Point";
void welcome() {
System.out.println("Welcome to " + shop);
}
public static void main(String[] args) {
Main m = new Main();
System.out.println(m.shop);
m.welcome();
}
}How it works: instance members need an object. Inside the static main we create one and use it through the reference m.
Static block for a lookup table
Fill a static array of state codes in a static block, then look up a code by index.
codes: MH, KA, TN, DL; look up index 2
Looking up... State table ready TN MH
Show solution and explanation
class States {
static String[] codes = new String[4];
static {
codes[0] = "MH";
codes[1] = "KA";
codes[2] = "TN";
codes[3] = "DL";
System.out.println("State table ready");
}
static String at(int i) {
return codes[i];
}
}
public class Main {
public static void main(String[] args) {
System.out.println("Looking up...");
System.out.println(States.at(2));
System.out.println(States.at(0));
}
}How it works: the static block runs once, when States is first used, which is after “Looking up...” has printed. The second lookup does not run it again.
Instance or static? Mixed counters
A video has its own view count, and the platform has a total view count across all videos. Model both and play two videos a few times.
video A played 3 times, video B played 2 times
Java in 10 min: 3 UPI explained: 2 Platform total: 5
Show solution and explanation
class Video {
static int totalViews = 0;
String title;
int views = 0;
Video(String title) {
this.title = title;
}
void play() {
views++;
totalViews++;
}
}
public class Main {
public static void main(String[] args) {
Video a = new Video("Java in 10 min");
Video b = new Video("UPI explained");
a.play(); a.play(); a.play();
b.play(); b.play();
System.out.println(a.title + ": " + a.views);
System.out.println(b.title + ": " + b.views);
System.out.println("Platform total: " + Video.totalViews);
}
}How it works: one play() updates both: the video's own counter and the class-wide total. Asking “does this differ per object?” decides static or not.
Currency converter with a shared rate
A travel app converts rupees to dollars. The exchange rate is the same for every conversion and changes during the day. Write a static rate and a static toUsd method, convert, update the rate, convert again.
rate 83.0 then 83.5; convert Rs 8300 and Rs 16700
$100.0 $201.2 $99.4
Show solution and explanation
class Fx {
static double inrPerUsd = 83.0;
static double toUsd(double inr) {
return Math.round(inr / inrPerUsd * 100) / 100.0;
}
}
public class Main {
public static void main(String[] args) {
System.out.println("$" + Fx.toUsd(8300));
System.out.println("$" + Fx.toUsd(16700));
Fx.inrPerUsd = 83.5;
System.out.println("$" + Fx.toUsd(8300));
}
}How it works: the rate is shared by every conversion, so it's static, and the method uses nothing else. Rounding to cents uses the trick from Lesson 2.4. (Real apps fetch the rate from a service and keep it in a config object.)
Seat limit for an event
An event has 3 seats. A static counter tracks seats booked across all Ticket objects; booking fails once the limit is reached.
booking requests: Asha, Ravi, Meena, Kabir
Asha: seat 1 Ravi: seat 2 Meena: seat 3 Kabir: sold out Booked 3 of 3
Show solution and explanation
class Ticket {
static final int CAPACITY = 3;
static int booked = 0;
static boolean book(String name) {
if (booked >= CAPACITY) {
System.out.println(name + ": sold out");
return false;
}
booked++;
System.out.println(name + ": seat " + booked);
return true;
}
}
public class Main {
public static void main(String[] args) {
String[] people = {"Asha", "Ravi", "Meena", "Kabir"};
for (String p : people) {
Ticket.book(p);
}
System.out.println("Booked " + Ticket.booked + " of " + Ticket.CAPACITY);
}
}How it works: the capacity is a constant and the booked count is shared state. Both belong to the event, not to one ticket. (With many simultaneous users, the check-and-increment must be synchronized, Lesson 12.4.)
Unique invoice numbers per financial year
Invoices are numbered like FY25-0001. Use a static constant for the year prefix and a static counter, and format the number with 4 digits.
three invoices
FY25-0001 FY25-0002 FY25-0003
Show solution and explanation
class Invoice {
static final String FY = "FY25";
static int last = 0;
String no;
Invoice() {
last++;
no = FY + "-" + String.format("%04d", last);
}
}
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 3; i++) {
System.out.println(new Invoice().no);
}
}
}How it works: %04d pads the number to 4 digits with zeros (Lesson 5.6's String.format). The counter is shared, so numbers never repeat within a run; a real system would store the last number in a database.
Real-world scenario questions (asked in company interviews)
Interviewers use static to see whether you understand shared state. Decide your answer, then open the model answer.
Every cart shows the same items
In a food-ordering app, every user suddenly sees the same cart. The Cart class has static List<String> items = new ArrayList<>();. What's wrong?
The interviewer is checking: do you know that static means one copy for the whole class?
Show a strong answer
itemsis static, so there is one list for all carts. Every user adds to and reads from the same list.- Each cart needs its own items: remove
staticso the list becomes an instance field created per object. - On a server, static data is also shared across all requests and threads, which can leak one customer's data to another.
Avoid: “clear the list after each order”. That hides the design error and still mixes concurrent users.
Static utility or object?
A team has InterestCalculator with only static methods. Now different products need different rules (savings, FD, senior citizen). How would you evolve it?
The interviewer is checking: do you know the limits of static methods?
Show a strong answer
- Static methods can't be overridden, so you can't plug in different rules per product.
- Turn the rule into an interface (
InterestRule) with one implementation per product, and pass the right object in (Lessons 7.5–7.7). - Keep genuinely stateless helpers static (rounding to paise, for example).
Avoid: adding a growing if-else chain on product type inside a static method.
Duplicate order numbers
Order IDs come from static int next = 1000; and id = next++; in the constructor. Under sale-day load, two orders got the same ID. Why, and how do you fix it?
The interviewer is checking: can you connect static shared state with thread safety?
Show a strong answer
next++is read, add, write: two threads can read the same value before either writes back (a race condition, Lesson 12.4).- Use
static final AtomicLong nextandnext.incrementAndGet(), or a synchronized method. - With several servers, an in-memory counter isn't enough at all: use a database sequence or a UUID.
Avoid: saying static fields are “thread-safe because there's only one copy”. One shared copy is exactly the problem.
Tests pass alone but fail together
Each test class passes when run alone, but the full test suite fails randomly. The code keeps a static Map cache of discounts that some tests modify. What's going on?
The interviewer is checking: do you understand static state's lifetime?
Show a strong answer
- Static fields live as long as the class is loaded, usually the whole test run, so one test's changes leak into the next.
- Make the cache an instance field of a service object created per test, or reset it explicitly in test setup.
- In production, static caches also need a size limit and an expiry policy.
Avoid: fixing it by forcing a test order.