The static keyword

Every bank account has its own balance, but they all share the bank's interest rate. Every token at a clinic is different, but one counter hands them out. Things that belong to the class as a whole, not to any single object, are marked static. You'll see where static data lives, why main is static, and the error every beginner meets: non-static variable cannot be referenced from a static context.

Module 6 · OOP Basics⏱ 22 minBeginner8 practice problems
1 The story

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.

#1 Accountbalance = 5000 #2 Accountbalance = 12000 #3 Accountbalance = 800 class Account (one copy) static double rate = 6.5 static int count = 3 myphatshala.in
Riya

Sir, every account has its own copy of the rate. When the rate changes, I have to loop over all of them.

Arjun Sir

Does the rate belong to Riya's account or Kabir's account?

Riya

Neither. It belongs to the bank… to accounts in general.

Arjun Sir

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.

2 Definition

What does static mean?

Formal definition (write this in exams)

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.

In simple words

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

Instance variableA field without static. Each object has its own copy.
Static (class) variableOne copy per class, shared by all its objects.
Static methodCalled on the class: Math.sqrt(16). No object needed, no this.
Static contextCode inside a static method or static block. There is no current object there.
Static blockstatic { … }: runs once when the class is first initialised.
Utility classA class with only static methods, like Math or Arrays.

Instance vs static at a glance

Instance memberStatic member
Belongs toEach objectThe class
How many copiesOne per objectExactly one
Created whennew creates the objectThe class is initialised (first use)
Accessed asacc.balance, acc.deposit(…)Account.rate, Math.max(…)
Can use this?YesNo
Typical useData that differs per objectShared 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.

3 Types and ways to use it

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;

Account.count

Static methods

Work that needs no object state: Math.max, Integer.parseInt, Arrays.sort, factory methods like List.of.

GstUtil.gst(price)

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
    }
}
30 12.566370614359172

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);
    }
}
main starts Config loading... 18 18

“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.

4 Step by step

Static and instance members working together

  1. Declare which data is shared

    class Account {
        static double rate = 7.0;   // one for all accounts
        static int count = 0;       // how many accounts exist
        double balance;             // one per account
    When the class is initialised, the JVM creates storage for rate and count once, with the class. No object exists yet.
  2. Update the shared counter in the constructor

        Account(double opening) {
            balance = opening;   // this object's field
            count++;             // the class's field
        }
    Each new Account(…) creates a fresh balance inside the new object, but all of them increment the same count.
  3. Instance methods can read static fields

        double yearlyInterest() {
            return balance * rate / 100;   // own balance, shared rate
        }
    Inside an instance method there is a current object (this), and the class is always reachable, so both kinds of member are available.
  4. Static methods have no current object

        static void setRate(double r) {
            rate = r;           // fine: static field
            // balance = 0;     // error: which account's balance?
        }
    A static method runs without this. Writing balance there 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.
  5. Call static members through the class name

    Account.setRate(6.5);
    System.out.println(Account.count + " accounts at " + Account.rate + "%");
    You can write a1.rate, but it hides the fact that the value is shared. IDEs warn about it; use the class name.
5 See it happen

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.

Instance fields vs static fields 6 steps
What you see // class Account is first used Account a = new Account(5000); Account b = new Account(12000); a.yearlyInterest(); b.yearlyInterest(); Account.setRate(6.5); a.yearlyInterest(); b.yearlyInterest(); accounts: 1 accounts: 2 a: 350.0 b: 840.0 rate changed once a: 325.0 b: 780.0 The static fields exist before any account. A new object; the shared counter becomes 1. Another object; the same counter becomes 2. Both use the same 7% rate. One assignment, no loop over accounts. Every account uses the new rate at once. myphatshala.in
Behind the screen class Account (statics: one copy) rate = 7.0 rate = 6.5 count = 0 count = 1 count = 2 HEAP: objects #1 Account balance = 5000.0 #2 Account balance = 12000.0 setRate is static: no this, no object needed. balance here → compile error Class initialised: statics created once. Objects hold only instance fields. count is not inside the objects. Both objects read the same rate. Only the class's copy changes. Shared data changed in one place. myphatshala.in
6 Real-world use

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.

static int next shared by every Token 5 steps
Animated example class Token (one copy) static next = 101 static next = 102 static next = 103 static next = 104 static next = 101 #1 Token patient=Asha number=101 #2 Token patient=Ravi number=102 #3 Token patient=Meena number=103 Token.next = 101; (a reset by mistake) next token: 101 again! 1 counter, 3 objects, 3 different numbers myphatshala.in
static finalGST = 18

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.

Rule→static final constant→Used everywhere
Math.

2. Utility classes

Math, Arrays, Collections, Objects and your own DateUtils or GstUtil: groups of static methods that need no object state.

Input→Util.method(input)→Result
of(…)

3. Factory methods

List.of(…), Integer.valueOf(…), LocalDate.of(2025, 1, 26). Static methods that create objects, often reusing cached ones.

Values→Type.of(…)→Ready object

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.

new Order()→static counter++→Order #1042

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.

7 Run the code

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());
    }
}
2 accounts at 7.0% Riya: 350.0, Kabir: 840.0 Riya: 325.0, Kabir: 780.0
  • 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 no this.
  • Account.countRead through the class name, which makes it obvious the value is shared.
8 Line by line

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.

Example 1Retail · GST

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.

Input
price 1200 at 18%, price 450 at 5%
Expected output
GST on cover: Rs 216
GST on book: Rs 22

Approach

  1. Put the logic in static int amount(int price, int rate).
  2. Call it through the class name: Gst.amount(…).
  3. No Gst object 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.

Example 2Travel · bookings

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.

Input
passengers Asha, Ravi, Meena
Expected output
MP-1001 Asha
MP-1002 Ravi
Bookings made: 2

Approach

  1. static final String PREFIX = "MP-" is a constant (final statics aren't shown in the trace: they never change).
  2. static int counter = 1000 is shared and incremented in the constructor.
  3. Each object stores its own id String.

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.

Example 3Banking · settings

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.

Input
minimum 1000, then 3000; balances 2500 and 800
Expected output
a pays fee: false, b pays fee: true
a pays fee: true, b pays fee: true

Approach

  1. static int minBalance is shared by all accounts.
  2. An instance method compares this account's balance with the shared minimum.
  3. Account.minBalance = 3000 changes 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.

9 Quiz and revision

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(), no this, 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 static drops the class name.
  • main is 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.

P1Easy

Count objects created

Write a class Student with a static counter that increases in the constructor. Create three students and print the count.

Input
Riya, Kabir, Asha
Expected output
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);
    }
}
Students: 3

How it works: each constructor call increments the same field. The objects aren't even stored in variables, yet the count is right.

P2Easy

A static utility method

Write MathUtil.isEven(int n) and MathUtil.square(int n) as static methods and call them without creating an object.

Input
isEven(7), square(12)
Expected output
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));
    }
}
false 144

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.

P3Easy

Fix the static context error

This doesn't compile: main uses the instance field shop directly. Fix it by creating an object.

Input
shop = "Chai Point"
Expected output
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();
    }
}
Chai Point Welcome to Chai Point

How it works: instance members need an object. Inside the static main we create one and use it through the reference m.

P4Medium

Static block for a lookup table

Fill a static array of state codes in a static block, then look up a code by index.

Input
codes: MH, KA, TN, DL; look up index 2
Expected output
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));
    }
}
Looking up... State table ready TN MH

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.

P5Medium

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.

Input
video A played 3 times, video B played 2 times
Expected output
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);
    }
}
Java in 10 min: 3 UPI explained: 2 Platform total: 5

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.

P6Business problem

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.

Input
rate 83.0 then 83.5; convert Rs 8300 and Rs 16700
Expected output
$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));
    }
}
$100.0 $201.2 $99.4

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.)

P7Business problem

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.

Input
booking requests: Asha, Ravi, Meena, Kabir
Expected output
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);
    }
}
Asha: seat 1 Ravi: seat 2 Meena: seat 3 Kabir: sold out Booked 3 of 3

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.)

P8Business problem

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.

Input
three invoices
Expected output
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);
        }
    }
}
FY25-0001 FY25-0002 FY25-0003

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.

Food delivery · bug huntFresher

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
  • items is 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 static so 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.

Banking · design1–3 years

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.

E-commerce · concurrency1–3 years

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 next and next.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.

Testing · code review3+ years

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.