static Keyword in Java: Variables, Methods, Blocks and Nested Classes Explained

  • Last Updated: July 24, 2026
  • By: javahandson
  • Series
img

static Keyword in Java: Variables, Methods, Blocks and Nested Classes Explained

Learn the static keyword in Java with clear examples. Covers static variables, methods, blocks, nested classes, class loading order and interview questions.

1. Introduction

You write a class. You create three objects from it. Then you notice something odd. Each object carries its own copy of every field. Change one, and the other two stay the same.

Most of the time that is exactly what you want. But sometimes you need one shared value. One counter for the whole class. One setting that every object reads.

The static keyword in Java solves that problem. It ties a member to the class itself, not to any single object. So there is only one copy, and everyone shares it.

This idea shows up everywhere. Think of Math.PI or main(). Both are static, and you have used them since day one.

Here is what we will cover:

  • What static really means, in plain words
  • Static variables, and how they differ from instance fields
  • Class methods, and the rules they must follow
  • Initialisation blocks, and when the JVM runs them
  • Nested classes marked static, and why they exist
  • Class loading order, which trips up a lot of people
  • Common mistakes and the interview questions that follow

You only need basic class and object knowledge. If you have written a constructor, you are ready.

static vs instance memory in java

2. What Does static Actually Mean?

The word static sounds like it means unchanging. That is misleading. A static variable can change all day long.

In Java, static means the member belongs to the class. It does not belong to any object made from that class.

2.1 One Copy, Shared by Everyone

Picture a classroom. Every student has their own name and their own roll number. Those are instance fields.

Now picture the room number written on the door. Every student in that room shares it. Nobody carries a private copy. That is a static field.

So the rule is simple. Instance members are per object. Static members are per class.

This shows up the moment you print things. Ask two students for their name and you get two answers. Ask them for the room number and you get one.

Memory works the same way. When the JVM loads a class, it reserves space for the static fields once. That space sits in the class area, which modern Java calls Metaspace.

Instance fields take a different route. They live on the heap, inside each object, and they appear only when you call new.

2.2 Where static Can Be Applied

Java lets you mark four things as static:

  • Variables, also called class variables
  • Methods, also called class methods
  • Blocks, which run once at class load time
  • Nested classes, which sit inside another class

You cannot mark a top-level class as static. That is a compile error. Only a nested class gets that option.

Local variables also reject static. A variable inside a method belongs to that method call, so the keyword makes no sense there.

Constructors refuse it too. A constructor exists to build one object, so tying it to the class would defeat its purpose.

And abstract never pairs with static. Abstract means a subclass must supply the body, while static means the call binds early with no subclass involved.

2.3 Access Without an Object

Because a static member belongs to the class, you can reach it through the class name. No object needed.

System.out.println(Math.PI);        // 3.141592653589793
int max = Integer.parseInt("42");   // no Integer object created
double r = Math.sqrt(81);           // 9.0

Notice the pattern. You never wrote new Math(). The class name was enough.

That is the everyday payoff of static. Utility values and helper methods stay one call away.

Compare that with a normal method. To call it, you first need an object sitting in memory.

Scanner sc = new Scanner(System.in);   // object needed first
int n = sc.nextInt();                  // instance method
 
int m = Integer.parseInt("42");        // static, no object at all

Both lines read a number. Only one of them made you build something first.

3. Static Variables

A static variable is declared inside a class but outside any method, with the static keyword in front. Java also calls it a class variable.

3.1 A Simple Counter Example

Counting objects is the classic use case. Every constructor call bumps the same shared number.

class Student {
    static int count = 0;   // shared by all Student objects
    String name;            // one per object
 
    Student(String name) {
        this.name = name;
        count++;            // increments the single shared copy
    }
}
 
public class Demo {
    public static void main(String[] args) {
        new Student("Amy");
        new Student("Ben");
        new Student("Cara");
 
        System.out.println(Student.count);   // 3
    }
}

Three objects were created, yet count printed 3 and not 1. Each constructor touched the very same variable.

Meanwhile every Student holds its own name. Amy, Ben and Cara never overwrite each other.

Try flipping count to a normal field and run it again. Now every object starts at zero, bumps to one, and stops there.

That tiny keyword changed the meaning completely. One word decides whether you count objects or just count to one, three times over.

3.2 Static vs Instance Variables

Seeing them side by side makes the difference click.

Feature Static variable Instance variable
Belongs to The class Each object
Number of copies Exactly one One per object
Memory area Class area (Metaspace) Heap, inside the object
Created when Class is loaded Object is created
Accessed by ClassName.field objectRef.field
Default value 0, false or null 0, false or null

One line stands out. Static variables come alive at class load, well before your first object exists.

Default values behave identically in both cases. An uninitialised int reads 0, a boolean reads false, and an object reference reads null.

Local variables break that pattern. The compiler refuses to read one until you assign it, which catches a lot of bugs early.

Java allows you to read a static field through an object reference. The compiler accepts it, though the result confuses readers.

Student s1 = new Student("Amy");
Student s2 = new Student("Ben");
 
s1.count = 100;                     // legal, but poor style
System.out.println(s2.count);       // 100
System.out.println(Student.count);  // 100

Writing through s1 changed what s2 sees. Nothing was copied. There was only ever one box.

So prefer Student.count in your code. It says exactly what is happening.

Most IDEs flag s1.count with a warning for this exact reason. The code implies per-object data, and the reader has to check the declaration to learn otherwise.

Same idea applies to methods. Write MathUtil.square(5) rather than creating an object just to call it.

3.4 Constants: static plus final

Pair static with final and you get a constant. One shared copy that nobody can reassign.

class Config {
    static final int MAX_USERS = 100;
    static final String APP_NAME = "JavaHandsOn";
}
 
// Config.MAX_USERS = 200;   // compile error: cannot assign a final variable

By convention these names use capital letters with underscores. That signals a constant at a glance.

One caution though. Marking a reference final only locks the reference, not the object it points to.

class Registry {
    static final List<String> NAMES = new ArrayList<>();
}
 
Registry.NAMES.add("Amy");     // allowed, the list itself is mutable
// Registry.NAMES = new ArrayList<>();   // compile error

The list can still grow. Only the variable is frozen.

Beginners hit this one hard. They mark a collection final, assume it is locked, then watch other code add items to it freely.

If you want a genuinely fixed collection, wrap it. List.copyOf() and Collections.unmodifiableList() both return something that rejects changes.

class Registry {
    static final List<String> NAMES = List.of("Amy", "Ben");
}
 
// Registry.NAMES.add("Cara");   // throws UnsupportedOperationException

Now both the variable and the contents stay put.

4. Static Methods

A static method belongs to the class too. Call it with the class name, and skip object creation entirely.

4.1 Declaring and Calling One

class MathUtil {
    static int square(int n) {
        return n * n;
    }
 
    static boolean isEven(int n) {
        return n % 2 == 0;
    }
}
 
public class Demo {
    public static void main(String[] args) {
        System.out.println(MathUtil.square(5));     // 25
        System.out.println(MathUtil.isEven(7));     // false
    }
}

No MathUtil object appears anywhere. The class name carries the call.

That is why helper classes across the JDK lean on static methods. Collections.sort() and Arrays.asList() follow the same idea.

Look at what these methods have in common. Each one takes input, computes something, and returns a result.

None of them remember anything between calls. Call square(5) a hundred times and you get 25 every single time.

That property is your best signal. When a method needs no object state to do its job, static usually fits.

4.2 The Big Rule: No this, No Instance Members

A static method runs without any object. So there is no this reference inside it.

Follow that thought and one restriction appears. Static code cannot touch instance fields or instance methods directly.

class Example {
    int instanceValue = 10;
    static int staticValue = 20;
 
    static void show() {
        System.out.println(staticValue);      // fine
        // System.out.println(instanceValue); // compile error
        // helper();                          // compile error
    }
 
    void helper() { }
}

The reason is not arbitrary. Which object’s instanceValue would it even print? There may be zero objects, or a thousand.

There is a way around it, of course. Pass an object in, then read its fields through that reference.

class Example {
    int instanceValue = 10;
 
    static void show(Example e) {
        System.out.println(e.instanceValue);   // works, we have an object now
    }
}

Now the method knows whose value to print. The ambiguity is gone.

Another workaround exists too. Create an object right inside the static method, then use it.

class Example {
    int instanceValue = 10;
 
    public static void main(String[] args) {
        Example e = new Example();
        System.out.println(e.instanceValue);   // 10
    }
}

You have probably written this pattern already. It is how main() reaches the rest of your class.

4.3 The Other Direction Works Fine

An instance method can freely call static members. It already has an object, and the class is definitely loaded.

class Counter {
    static int total = 0;
    int myCount = 0;
 
    void increment() {
        total++;       // static access from an instance method: allowed
        myCount++;     // instance access: also allowed
    }
}

So the restriction only points one way. Static cannot see instance, but instance can see static.

4.4 Why main() Is Static

Here is a question interviewers love. Why does main() carry the static keyword?

Think about the startup sequence. The JVM needs an entry point before any of your objects exist.

If main() were an instance method, the JVM would have to build an object first. But which constructor should it call? What arguments should it pass?

Marking main() static sidesteps all of that. The JVM loads your class and calls the method straight away.

Look at the full signature and every piece has a purpose:

  • public, so the JVM can reach it from outside your class
  • static, so no object is needed before the call
  • void, because there is nobody left to receive a return value
  • String[] args, which carries command-line arguments in

Drop the static keyword and the code still compiles. It simply fails at runtime with a message about main not being static.

INTERVIEW INSIGHT
If main() were not static, the JVM would need an object of your class before it could start. That means guessing which constructor to call and what to pass it. Static removes the guesswork, so the JVM can invoke main() right after loading the class.

4.5 Static Methods Cannot Be Overridden

Overriding works through dynamic dispatch. At runtime the JVM checks the actual object type and picks the right method.

Static methods skip that machinery. Calls bind at compile time using the reference type. The behaviour is called method hiding, not overriding.

class Parent {
    static void greet() { System.out.println("Parent greet"); }
    void hello()        { System.out.println("Parent hello"); }
}
 
class Child extends Parent {
    static void greet() { System.out.println("Child greet"); }   // hiding
    void hello()        { System.out.println("Child hello"); }   // overriding
}
 
public class Demo {
    public static void main(String[] args) {
        Parent p = new Child();
        p.greet();    // Parent greet  <- reference type wins
        p.hello();    // Child hello   <- object type wins
    }
}

Read those two lines carefully. Same reference, two different rules.

The instance call looked at the real object, a Child. The static call only looked at the declared type, Parent.

A few extra rules follow from this. The compiler enforces them strictly:

  • A static method cannot hide an instance method of the parent
  • An instance method cannot override a static method of the parent
  • Both attempts fail at compile time, not at runtime

There is a practical takeaway here as well. Calling a static method through an object reference hides which class actually runs, so reach for the class name instead.

INTERVIEW INSIGHT
Hiding resolves at compile time from the reference type. Overriding resolves at runtime from the object type. That single difference explains why p.greet() printed the parent version while p.hello() printed the child version.

5. Static Blocks

A static block is a chunk of code wrapped in braces with static in front. It sits directly inside the class body.

5.1 Basic Syntax and Timing

The JVM runs a static block exactly once, when it loads the class. That happens before any object is created and before main() runs.

class Loader {
    static int value;
 
    static {
        System.out.println("Static block running");
        value = 42;
    }
 
    Loader() {
        System.out.println("Constructor running");
    }
}
 
public class Demo {
    public static void main(String[] args) {
        System.out.println("main starts");
        new Loader();
        new Loader();
    }
}

Here is the output:

main starts
Static block running
Constructor running
Constructor running

Notice the static block printed once, even though two objects appeared. Constructors ran twice, as expected.

Also notice it printed after “main starts”. The Loader class only loads at its first use.

Move the new Loader() line above the print and the order flips. Class loading follows your code, not the file layout.

One more detail matters here. Static blocks run inside the class initialiser, so any exception they throw becomes an ExceptionInInitializerError.

That error is nasty to debug. The class never finishes loading, and every later use of it fails with a different, more confusing error.

5.2 When Would You Use One?

Static blocks handle setup that a simple assignment cannot express. Typical jobs include:

  • Filling a static collection with starting values
  • Reading configuration once at startup
  • Wrapping risky initialisation in a try-catch
  • Computing a constant that needs a few steps
class CountryCodes {
    static final Map<String, String> CODES = new HashMap<>();
 
    static {
        CODES.put("IN", "India");
        CODES.put("US", "United States");
        CODES.put("JP", "Japan");
    }
}

You could not do that with a one-line initialiser. The block gives you room to write real statements.

Modern Java softens this a bit. Map.of() and List.of() handle small fixed collections in a single line, so the block is not always needed.

But loops, conditionals and try-catch still need real statements. That is where a static block keeps earning its place.

class Squares {
    static final int[] TABLE = new int[10];
 
    static {
        for (int i = 0; i < TABLE.length; i++) {
            TABLE[i] = i * i;
        }
    }
}

Ten values, computed once, ready before anyone asks for them.

5.3 Multiple Blocks Run in Order

A class may hold several static blocks. The JVM runs them top to bottom, in source order.

class Ordered {
    static { System.out.println("First block"); }
    static int x = printAndReturn();
    static { System.out.println("Third block"); }
 
    static int printAndReturn() {
        System.out.println("Second: field initialiser");
        return 5;
    }
}

Static field initialisers join the same queue. Position in the file decides who goes first.

First block
Second: field initialiser
Third block

So you cannot reference a static field above the line that declares it. The compiler calls this an illegal forward reference.

Keep declarations near the top and blocks below them. That ordering avoids the whole class of problem.

5.4 Static Block vs Constructor vs Instance Block

Three initialisation tools, three different jobs. This table sorts them out.

Feature Static block Instance block Constructor
Runs when Class loads Object is created Object is created
How many times Once ever Once per object Once per object
Runs before main() and constructors The constructor body Nothing after it
Can use this No Yes Yes
Takes parameters No No Yes
Typical use One-time class setup Shared object setup Per-object setup

Instance blocks are rarer in real code. Most developers put that logic straight into the constructor.

6. Static Nested Classes

Java lets you declare a class inside another class. Add static to that inner declaration and the rules change quite a bit.

6.1 Static Nested vs Inner Class

A non-static nested class is called an inner class. It holds a hidden link to an outer object, so you need that object to create one.

A static nested class carries no such link. You create it using only the outer class name.

class Outer {
    private int outerField = 10;
    private static int staticField = 20;
 
    static class StaticNested {
        void show() {
            System.out.println(staticField);   // fine
            // System.out.println(outerField); // compile error
        }
    }
 
    class Inner {
        void show() {
            System.out.println(outerField);    // fine, has outer reference
            System.out.println(staticField);   // also fine
        }
    }
}

Creating them looks different too:

Outer.StaticNested nested = new Outer.StaticNested();   // no Outer object
 
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();                  // needs an Outer object

That odd outer.new syntax is a strong hint. An inner class truly depends on its enclosing object.

6.2 Why Prefer Static Nested Classes

The hidden outer reference in an inner class is not free. It costs memory, and it can keep the outer object alive longer than you expect.

So a common guideline says this. If the nested class does not use outer instance state, mark it static.

  • No hidden reference, so a smaller memory footprint
  • No accidental leak of the outer object
  • Easier to instantiate and test on its own
  • Clearer intent for anyone reading the code

You see this pattern constantly in the JDK. Map.Entry implementations and builder classes are usually static nested classes.

class Pizza {
    private final String size;
    private final boolean extraCheese;
 
    private Pizza(Builder b) {
        this.size = b.size;
        this.extraCheese = b.extraCheese;
    }
 
    static class Builder {
        private String size = "medium";
        private boolean extraCheese = false;
 
        Builder size(String s)        { this.size = s; return this; }
        Builder extraCheese(boolean e) { this.extraCheese = e; return this; }
        Pizza build()                  { return new Pizza(this); }
    }
}
 
Pizza p = new Pizza.Builder().size("large").extraCheese(true).build();

The builder never touches Pizza instance state. Static is the right fit.

The leak risk is worth spelling out. Suppose an inner class object gets stored in a long-lived collection somewhere.

That inner object still points back at its outer object. So the outer one cannot be collected either, even though nothing else uses it.

Android developers ran into this constantly with inner-class handlers holding on to whole screens. Marking the nested class static broke the chain.

7. Class Loading and Initialisation Order

Order questions come up a lot, both in interviews and in real bugs. Let us pin the sequence down.

7.1 When Does a Class Load?

The JVM loads a class lazily, at first active use. Any of these triggers it:

  • Creating the first object of that class
  • Calling one of its static methods
  • Reading or writing a static field, unless it is a compile-time constant
  • Loading a subclass, which loads the parent first

That last bullet has an exception worth knowing. A static final field with a literal value gets inlined at compile time.

class Constants {
    static final int MAX = 100;     // compile-time constant, gets inlined
    static { System.out.println("Constants loaded"); }
}
 
System.out.println(Constants.MAX);  // prints 100, no "Constants loaded"

The compiler replaced Constants.MAX with the literal 100. The class was never touched at runtime.

This inlining has a real consequence in larger projects. Change MAX and recompile only that one file, and other classes keep using the old value.

A clean rebuild fixes it. Still, it explains some very confusing bug reports.

7.2 The Full Order With Inheritance

Mix a parent, a child, static blocks, instance blocks and constructors. The sequence is fixed.

class Parent {
    static { System.out.println("1. Parent static block"); }
    { System.out.println("3. Parent instance block"); }
    Parent() { System.out.println("4. Parent constructor"); }
}
 
class Child extends Parent {
    static { System.out.println("2. Child static block"); }
    { System.out.println("5. Child instance block"); }
    Child() { System.out.println("6. Child constructor"); }
}
 
public class Demo {
    public static void main(String[] args) {
        new Child();
        System.out.println("---");
        new Child();
    }
}

The output looks like this:

1. Parent static block
2. Child static block
3. Parent instance block
4. Parent constructor
5. Child instance block
6. Child constructor
---
3. Parent instance block
4. Parent constructor
5. Child instance block
6. Child constructor

Read the second object carefully. Static blocks vanished from the output because the classes were already loaded.

So the rule reads like this. All static work happens first and once. Instance work repeats for every object, parent before child.

static initialisation order
INTERVIEW INSIGHT
A reliable answer walks two phases. Phase one is class loading: parent static blocks and static fields, then child static blocks, and this happens only once. Phase two repeats per object: parent instance block, parent constructor, child instance block, child constructor.

8. Common Mistakes and Gotchas

Some static bugs show up again and again. Here are the ones worth memorising.

8.1 Thinking static Means Constant

The name misleads beginners. A static variable is shared, not frozen.

class Counter {
    static int count = 0;
}
 
Counter.count = 5;
Counter.count = 99;     // perfectly legal

Add final if you actually want a constant. Static alone gives you sharing only.

8.2 Shared Mutable State in Multithreaded Code

This one causes real production bugs. Every thread sees the same static variable, so races are easy to create.

class Unsafe {
    static int counter = 0;
 
    static void increment() {
        counter++;      // not atomic: read, add, write
    }
}

That single line is three operations underneath. Two threads can read the same value and each write back the same result, so one increment disappears.

Fixes exist. AtomicInteger, a synchronized block, or simply avoiding shared mutable state all work.

The safest habit is easy to state. Keep static fields immutable or thread-safe, and think twice before adding a mutable one.

import java.util.concurrent.atomic.AtomicInteger;
 
class Safe {
    static final AtomicInteger counter = new AtomicInteger();
 
    static void increment() {
        counter.incrementAndGet();   // atomic
    }
}

This version survives many threads. The increment happens as one indivisible step.

8.3 Static Fields and Memory Retention

A static field lives as long as its class stays loaded. In a typical application, that means for the whole run.

class Cache {
    static List<byte[]> data = new ArrayList<>();
 
    static void add(byte[] chunk) {
        data.add(chunk);      // nothing ever removes items
    }
}

Objects inside that list never become garbage. The static reference keeps them reachable forever.

So a static collection with no eviction policy is a leak waiting to happen. Clear it, cap it, or use a proper cache library.

Web applications feel this most. The class stays loaded for days, so anything you park in a static field stays with it.

Caffeine and Guava both offer caches with size limits and expiry. Reaching for one of those beats hand-rolling a static map.

8.4 Overusing static and Losing Testability

Static methods are convenient, which is exactly the trap. They are hard to replace in tests.

You cannot subclass a static method or inject a fake version through a constructor. Your test is stuck with the real implementation.

Good static candidates share one trait. They are pure utilities that depend only on their arguments.

  • Good fit: Math.max(), Integer.parseInt(), a string formatting helper
  • Poor fit: a service that calls a database or an external API
  • Poor fit: anything holding mutable application state

Frameworks reflect this preference. Spring builds instance beans and injects them, precisely so you can swap in a test double later.

Static utilities still belong in your code. Just keep them small, keep them pure, and keep your business logic out of them.

8.5 The NullPointerException That Never Comes

Here is a quirk that surprises people. Calling a static method through a null reference still works.

class Util {
    static void hello() { System.out.println("hello"); }
}
 
Util u = null;
u.hello();      // prints hello, no exception

The compiler resolved that call from the type Util, not from the value of u. The reference was never dereferenced.

Still, never write code like this. It only proves how binding works.

Change hello() to an instance method and the same line throws immediately. Now the JVM must find a real object, and there is none.

That contrast makes the point nicely. Static calls need a type, while instance calls need an actual object.

9. Quick Reference

Keep this table handy while the rules settle in.

Question Answer
Can a static method use this? No, there is no object involved
Can a static method call an instance method? Not directly, it needs an object reference
Can an instance method call a static method? Yes, always
Can a static method be overridden? No, it gets hidden instead
Can a top-level class be static? No, only a nested class
Can a local variable be static? No, that is a compile error
Can a constructor be static? No, constructors build objects
Can an abstract method be static? No, the two contradict each other
When does a static block run? Once, when the class loads
Where do static variables live? The class area, part of Metaspace

10. Interview Questions

Q: What does the static keyword mean in Java?

A: It ties a member to the class rather than to any object. Only one copy exists, and every object shares it. You can access a static member using the class name, without creating an object first.

Q: Why is the main method static in Java?

A: The JVM needs an entry point before any object exists. If main() were an instance method, the JVM would have to guess which constructor to call and what arguments to pass. Static removes that problem, so the JVM can invoke main() right after loading the class.

Q: Can a static method access instance variables?

A: Not directly. A static method runs without any object, so there is no this reference and no way to tell which object’s field to read. You can still access instance data by passing an object into the method or creating one inside it.

Q: Can we override a static method in Java?

A: No. Redeclaring a static method in a subclass is called method hiding, not overriding. Static calls bind at compile time from the reference type, while overridden instance calls bind at runtime from the actual object type.

Q: When does a static block run?

A: Exactly once, when the JVM loads the class. That happens before main() runs and before any object is created. If a class has several static blocks, they run top to bottom in source order.

Q: What is the initialization order of static blocks, instance blocks and constructors?

A: Class loading comes first and runs only once: parent static fields and blocks, then child static fields and blocks. Object creation repeats every time: parent instance block, parent constructor, child instance block, then child constructor.

Q: What is the difference between a static nested class and an inner class?

A: An inner class holds a hidden reference to its outer object, so you need an outer instance to create one. A static nested class carries no such reference and is created using only the outer class name. Prefer static when the nested class does not need outer instance state.

Q: Does static mean the value cannot change?

A: No. A static variable is shared, not frozen, and you can reassign it freely. Add final alongside static if you want a true constant that nobody can reassign.

Q: Why can static variables cause memory leaks?

A: A static field stays reachable as long as its class remains loaded, which is usually the whole application run. Anything stored in a static collection never becomes garbage unless you remove it, so a cache with no eviction policy grows forever.

Q: Are static variables thread safe?

A: No. Every thread sees the same static variable, so a plain counter++ can lose updates because it is really a read, an add and a write. Use AtomicInteger, a synchronized block, or keep static fields immutable.

11. Conclusion

Let us pull the threads together. The static keyword in Java attaches a member to the class rather than to any object.

A static variable gives you one shared copy. Class methods run without an object, which is why they cannot see instance state or use this.

Initialisation blocks handle one-time setup at class load. And a static nested class drops the hidden outer reference that inner classes carry.

Reach for static when a value or helper truly belongs to the class. Avoid it for mutable shared state, and watch out for the memory and testing costs.

Further Reading

Leave a Comment