Java static Keyword
Java static Keyword
The static keyword in Java means something belongs to the class rather than to any specific object. A static field is shared across every instance of the class. A static method can be called without creating an object. A static block runs once when the class is first loaded. Understanding static is not just about syntax — it is about knowing which things in your program genuinely belong to the class concept versus which things belong to individual objects.
Getting this wrong is common. Static fields used for per-object data, static methods that accidentally modify shared state, unnecessary use of static everywhere — these are consistent code review flags that separate junior from mid-level Java developers.
What Does static Mean in Java?
When you mark something static, you are saying: "this member belongs to the class, not to instances of the class." As a consequence:
- ›A static field has exactly one copy shared by all objects of the class
- ›A static method can be called on the class name without creating an object
- ›A static block executes once when the class is loaded by the JVM, before any object is created
- ›A static nested class can be instantiated without an instance of the outer class
The non-static equivalent of each — instance field, instance method, instance initialiser, inner class — exists per-object and requires an object to function.
Four Uses of the static Keyword
| Use | Syntax | Memory | When Created | Belongs To |
|---|---|---|---|---|
| Static field | static int count | Method Area (once) | Class loading | The class |
| Static method | static void reset() | Method Area | Class loading | The class |
| Static block | static { ... } | Executed once | Class loading | The class |
| Static nested class | static class Config | When instantiated | On new call | The class (not an instance) |
Static Fields — One Copy for All Objects
A static field (also called a class variable) has a single copy shared across every instance of the class. Changing it through one object or through the class name changes it for everyone.
1// File: AppConfig.java
2
3public class AppConfig {
4
5 // Static field — one value shared by all AppConfig objects (and the class itself)
6 public static final String APP_NAME = "DevStackFlow";
7 public static final String APP_VERSION = "2.1.0";
8 public static final int MAX_SESSIONS = 500;
9
10 // Instance field — each AppConfig object gets its own copy
11 private String environment;
12
13 public AppConfig(String environment) {
14 this.environment = environment;
15 }
16
17 public String getEnvironment() { return environment; }
18}1// File: StaticFieldDemo.java
2
3public class StaticFieldDemo {
4
5 public static void main(String[] args) {
6
7 // Access static fields directly on the class — no object needed
8 System.out.println("App : " + AppConfig.APP_NAME);
9 System.out.println("Version: " + AppConfig.APP_VERSION);
10 System.out.println("Max sessions: " + AppConfig.MAX_SESSIONS);
11
12 // Static fields are also accessible through object references (not recommended)
13 AppConfig devConfig = new AppConfig("DEVELOPMENT");
14 AppConfig prodConfig = new AppConfig("PRODUCTION");
15
16 // Both objects share the same APP_NAME — it belongs to the class
17 System.out.println("\ndev APP_NAME: " + devConfig.APP_NAME);
18 System.out.println("prod APP_NAME: " + prodConfig.APP_NAME);
19
20 // Instance fields are independent
21 System.out.println("\ndev environment: " + devConfig.getEnvironment());
22 System.out.println("prod environment: " + prodConfig.getEnvironment());
23 }
24}Output:
App : DevStackFlow
Version: 2.1.0
Max sessions: 500
dev APP_NAME: DevStackFlow
prod APP_NAME: DevStackFlow
dev environment: DEVELOPMENT
prod environment: PRODUCTION
APP_NAME is the same regardless of which object you access it through — there is only one copy in memory. environment is different for each object — each instance has its own copy. IntelliJ IDEA flags accessing a static field through an object reference (devConfig.APP_NAME) with a warning — it should always be AppConfig.APP_NAME to make the class-level nature clear.
Static Fields for Shared Counters
A common and legitimate use of static fields is tracking class-level state — like how many objects have been created.
1// File: DatabaseConnection.java
2
3public class DatabaseConnection {
4
5 // Tracks how many connections are currently active — shared state
6 private static int activeConnections = 0;
7 private static final int MAX_POOL_SIZE = 10;
8
9 private final String connectionId;
10 private final String databaseUrl;
11 private boolean isOpen;
12
13 public DatabaseConnection(String databaseUrl) {
14 if (activeConnections >= MAX_POOL_SIZE) {
15 throw new IllegalStateException("Connection pool exhausted. Max: " + MAX_POOL_SIZE);
16 }
17 this.connectionId = "CONN-" + (activeConnections + 1);
18 this.databaseUrl = databaseUrl;
19 this.isOpen = true;
20 activeConnections++;
21 }
22
23 public void close() {
24 if (isOpen) {
25 isOpen = false;
26 activeConnections--;
27 System.out.println(connectionId + " closed.");
28 }
29 }
30
31 public String getConnectionId() { return connectionId; }
32 public static int getActiveCount() { return activeConnections; }
33
34 public String getStatus() {
35 return connectionId + " | " + databaseUrl + " | Open: " + isOpen;
36 }
37}1// File: ConnectionPoolDemo.java
2
3public class ConnectionPoolDemo {
4
5 public static void main(String[] args) {
6
7 System.out.println("Active connections: " + DatabaseConnection.getActiveCount());
8
9 DatabaseConnection conn1 = new DatabaseConnection("jdbc:mysql://db1:3306/orders");
10 DatabaseConnection conn2 = new DatabaseConnection("jdbc:mysql://db1:3306/users");
11 DatabaseConnection conn3 = new DatabaseConnection("jdbc:mysql://db2:3306/analytics");
12
13 System.out.println("Active connections: " + DatabaseConnection.getActiveCount());
14
15 System.out.println(conn1.getStatus());
16 System.out.println(conn2.getStatus());
17 System.out.println(conn3.getStatus());
18
19 conn2.close();
20 System.out.println("\nActive after closing conn2: " + DatabaseConnection.getActiveCount());
21 }
22}Output:
Active connections: 0
Active connections: 3
CONN-1 | jdbc:mysql://db1:3306/orders | Open: true
CONN-2 | jdbc:mysql://db1:3306/users | Open: true
CONN-3 | jdbc:mysql://db2:3306/analytics | Open: true
Active after closing conn2: 2
activeConnections increments in the constructor of every new object and decrements when close() is called. It is shared state — there is no way to model "how many connections are open" as per-object data. This is a textbook legitimate use of a static field.
Static Methods — No Object Required
A static method belongs to the class and can be called without creating an instance. It can only access static fields and other static methods directly — it cannot access instance fields or call instance methods without an object reference.
1// File: MathUtils.java
2
3public class MathUtils {
4
5 // Private constructor — prevents instantiation of a utility class
6 private MathUtils() {}
7
8 // Static utility methods — no object state needed
9 public static double roundToTwoDecimals(double value) {
10 return Math.round(value * 100.0) / 100.0;
11 }
12
13 public static boolean isBetween(double value, double min, double max) {
14 return value >= min && value <= max;
15 }
16
17 public static double applyDiscount(double price, double discountPercent) {
18 if (discountPercent < 0 || discountPercent > 100) {
19 throw new IllegalArgumentException("Discount must be 0-100%: " + discountPercent);
20 }
21 return roundToTwoDecimals(price * (1 - discountPercent / 100.0));
22 }
23
24 public static double calculateGst(double basePrice) {
25 return roundToTwoDecimals(basePrice * 0.18);
26 }
27}1// File: StaticMethodDemo.java
2
3public class StaticMethodDemo {
4
5 public static void main(String[] args) {
6
7 // Called on the class — no MathUtils object created
8 double originalPrice = 1499.0;
9 double discountedPrice = MathUtils.applyDiscount(originalPrice, 15);
10 double gst = MathUtils.calculateGst(discountedPrice);
11 double finalPrice = discountedPrice + gst;
12
13 System.out.printf("Original price : Rs.%.2f%n", originalPrice);
14 System.out.printf("After 15%% disc : Rs.%.2f%n", discountedPrice);
15 System.out.printf("GST (18%%) : Rs.%.2f%n", gst);
16 System.out.printf("Final price : Rs.%.2f%n", finalPrice);
17
18 System.out.println("\nIs Rs.1500 in range Rs.1000–Rs.2000? "
19 + MathUtils.isBetween(1500, 1000, 2000));
20 }
21}Output:
Original price : Rs.1499.00
After 15% disc : Rs.1274.15
GST (18%) : Rs.229.35
Final price : Rs.1503.50
Is Rs.1500 in range Rs.1000–Rs.2000? true
MathUtils has a private constructor — it is a utility class that should never be instantiated. All operations are stateless — they take inputs and produce outputs without depending on any object state. This is the canonical use of static methods in Java, mirroring Math, Arrays, and Collections in the standard library.
Static Block — One-Time Class Initialisation
A static block (also called a static initialiser) runs once when the class is first loaded by the JVM — before any constructor runs and before any static field is directly accessed. Use it for complex initialisation logic that cannot be expressed in a single field declaration.
1// File: CountryCodeRegistry.java
2
3import java.util.Collections;
4import java.util.HashMap;
5import java.util.Map;
6
7public class CountryCodeRegistry {
8
9 // Static field — populated by the static block
10 private static final Map<String, String> COUNTRY_CODES;
11
12 // Static block — runs once at class load time
13 static {
14 Map<String, String> codes = new HashMap<>();
15 codes.put("IN", "India (+91)");
16 codes.put("US", "United States (+1)");
17 codes.put("GB", "United Kingdom (+44)");
18 codes.put("SG", "Singapore (+65)");
19 codes.put("AE", "UAE (+971)");
20 codes.put("AU", "Australia (+61)");
21
22 // Wrap in unmodifiable view — the map is final after loading
23 COUNTRY_CODES = Collections.unmodifiableMap(codes);
24
25 System.out.println("CountryCodeRegistry loaded: "
26 + COUNTRY_CODES.size() + " countries registered.");
27 }
28
29 private CountryCodeRegistry() {}
30
31 public static String getCountryInfo(String code) {
32 return COUNTRY_CODES.getOrDefault(code.toUpperCase(), "Unknown country code: " + code);
33 }
34
35 public static int getRegisteredCount() {
36 return COUNTRY_CODES.size();
37 }
38}1// File: StaticBlockDemo.java
2
3public class StaticBlockDemo {
4
5 public static void main(String[] args) {
6
7 // The static block runs the first time CountryCodeRegistry is used
8 System.out.println(CountryCodeRegistry.getCountryInfo("IN"));
9 System.out.println(CountryCodeRegistry.getCountryInfo("SG"));
10 System.out.println(CountryCodeRegistry.getCountryInfo("ZZ"));
11 System.out.println("Registered: " + CountryCodeRegistry.getRegisteredCount());
12 }
13}Output:
CountryCodeRegistry loaded: 6 countries registered.
India (+91)
Singapore (+65)
Unknown country code: ZZ
6
The static block runs exactly once — when CountryCodeRegistry is first referenced. The "loaded" message appears before the first lookup because that lookup triggers the class loading, which triggers the static block. No constructor runs; no object is created. The map is initialised in a controlled, thread-safe manner because class loading in the JVM is inherently thread-safe.
Static Nested Class
A static nested class is a class declared inside another class with the static modifier. Unlike an inner class, it does not hold an implicit reference to the outer class instance — it can be instantiated without an instance of the outer class.
1// File: HttpRequest.java
2
3public class HttpRequest {
4
5 private final String url;
6 private final String method;
7 private final String body;
8 private final int timeoutMs;
9
10 // Private constructor — use the nested Builder to create instances
11 private HttpRequest(Builder builder) {
12 this.url = builder.url;
13 this.method = builder.method;
14 this.body = builder.body;
15 this.timeoutMs = builder.timeoutMs;
16 }
17
18 public String getUrl() { return url; }
19 public String getMethod() { return method; }
20 public String getBody() { return body; }
21 public int getTimeoutMs(){ return timeoutMs; }
22
23 public String getSummary() {
24 return method + " " + url
25 + " | Timeout: " + timeoutMs + "ms"
26 + (body.isEmpty() ? "" : " | Body: " + body);
27 }
28
29 // Static nested class — can be used without an HttpRequest instance
30 public static class Builder {
31
32 private String url;
33 private String method = "GET";
34 private String body = "";
35 private int timeoutMs = 5000;
36
37 public Builder url(String url) {
38 this.url = url;
39 return this;
40 }
41
42 public Builder method(String method) {
43 this.method = method;
44 return this;
45 }
46
47 public Builder body(String body) {
48 this.body = body;
49 return this;
50 }
51
52 public Builder timeoutMs(int timeoutMs) {
53 this.timeoutMs = timeoutMs;
54 return this;
55 }
56
57 public HttpRequest build() {
58 if (url == null || url.isBlank()) {
59 throw new IllegalStateException("URL is required.");
60 }
61 return new HttpRequest(this);
62 }
63 }
64}1// File: StaticNestedClassDemo.java
2
3public class StaticNestedClassDemo {
4
5 public static void main(String[] args) {
6
7 // Builder is a static nested class — no HttpRequest instance needed to create it
8 HttpRequest getRequest = new HttpRequest.Builder()
9 .url("https://api.devstackflow.com/articles")
10 .timeoutMs(3000)
11 .build();
12
13 HttpRequest postRequest = new HttpRequest.Builder()
14 .url("https://api.devstackflow.com/articles")
15 .method("POST")
16 .body("{\"title\": \"Java static Keyword\"}")
17 .timeoutMs(10000)
18 .build();
19
20 System.out.println(getRequest.getSummary());
21 System.out.println(postRequest.getSummary());
22 }
23}Output:
GET https://api.devstackflow.com/articles | Timeout: 3000ms
POST https://api.devstackflow.com/articles | Timeout: 10000ms | Body: {"title": "Java static Keyword"}
HttpRequest.Builder is created directly without an HttpRequest object — that is the defining characteristic of a static nested class. The builder pattern with a static nested class is the standard Java pattern for constructing objects that have many optional fields.
static vs Instance — Comprehensive Comparison
| Aspect | static Member | Instance Member |
|---|---|---|
| Belongs to | The class | Each individual object |
| Memory location | Method Area — one copy | Heap — one copy per object |
| Created when | Class is loaded by JVM | Object is created with new |
| Accessed via | Class name (preferred) or object reference | Object reference only |
| Can access instance members | No — not without an object reference | Yes — can access both static and instance |
| Can be overridden | No — hidden in subclass instead | Yes — polymorphism applies |
| Thread safety | Needs synchronisation if mutable | Per-object — usually no shared state issue |
| Use case | Shared state, utility methods, constants | Per-object state and behaviour |
static Method vs Instance Method
| Aspect | Static Method | Instance Method |
|---|---|---|
| Called on | Class name | Object reference |
| Access to instance fields | No | Yes |
| Access to static fields | Yes | Yes |
Can use this | No | Yes |
| Can be overridden | No (hidden) | Yes |
| Overriding mechanism | Static binding (compile time) | Dynamic binding (runtime) |
| Typical use | Utility, factory, helpers | Object-specific behaviour |
Static Field vs Instance Field
| Aspect | Static Field | Instance Field |
|---|---|---|
| Copies in memory | One — shared by all objects | One per object |
| Memory location | Method Area | Heap (inside each object) |
| Scope | Entire class lifetime | Object lifetime |
| Default initialisation | Yes — at class loading | Yes — at object creation |
| Typical use | Counters, constants, shared config | Per-object data (name, balance, status) |
| Thread safety | Needs synchronisation if mutable | Usually safe — each object has own copy |
How static Works Internally in the JVM
When the JVM loads a class for the first time, it performs three steps:
Step 1: Loading
JVM reads the .class file and brings the bytecode into memory.
Step 2: Linking
Verifies the bytecode, prepares static fields by allocating
memory in the Method Area and setting default values.
(int → 0, double → 0.0, Object → null)
Step 3: Initialisation
Runs static field initialisers and static blocks in
the order they appear in the source code.
This happens exactly once per class per JVM.
Static members live in the Method Area (part of JVM memory) — not on the heap where objects live. This is why static fields persist for the lifetime of the class and why they are accessible without an object.
Real-World Example — Application Configuration System
The Business Problem
You are building the configuration management layer for a multi-environment Java backend — similar to what companies like Razorpay or CRED use for managing service configuration across development, staging, and production. The configuration values are loaded once at startup, shared across all service components, and should never be recreated. Static fields, a static block, and static methods are the natural fit.
Implementation
1// File: Environment.java
2
3public enum Environment {
4 DEVELOPMENT, STAGING, PRODUCTION
5}1// File: ServiceConfig.java
2
3import java.util.Collections;
4import java.util.HashMap;
5import java.util.Map;
6
7public final class ServiceConfig {
8
9 // Static fields — loaded once, shared across all components
10 private static final Environment CURRENT_ENV;
11 private static final String SERVICE_NAME;
12 private static final String BASE_API_URL;
13 private static final int REQUEST_TIMEOUT_MS;
14 private static final int MAX_RETRY_COUNT;
15 private static final Map<String, String> FEATURE_FLAGS;
16
17 // Static block — complex initialisation logic
18 static {
19 // In production this would read from environment variables or a config file
20 String envName = System.getProperty("app.env", "DEVELOPMENT");
21 CURRENT_ENV = Environment.valueOf(envName.toUpperCase());
22 SERVICE_NAME = "payment-service";
23
24 switch (CURRENT_ENV) {
25 case PRODUCTION -> {
26 BASE_API_URL = "https://api.razorpay.com/v1";
27 REQUEST_TIMEOUT_MS = 5000;
28 MAX_RETRY_COUNT = 3;
29 }
30 case STAGING -> {
31 BASE_API_URL = "https://staging-api.razorpay.com/v1";
32 REQUEST_TIMEOUT_MS = 10000;
33 MAX_RETRY_COUNT = 5;
34 }
35 default -> {
36 BASE_API_URL = "http://localhost:8080/mock/v1";
37 REQUEST_TIMEOUT_MS = 30000;
38 MAX_RETRY_COUNT = 1;
39 }
40 }
41
42 Map<String, String> flags = new HashMap<>();
43 flags.put("upi_enabled", CURRENT_ENV == Environment.PRODUCTION ? "true" : "true");
44 flags.put("bnpl_enabled", CURRENT_ENV == Environment.PRODUCTION ? "true" : "false");
45 flags.put("crypto_enabled", "false");
46 FEATURE_FLAGS = Collections.unmodifiableMap(flags);
47
48 System.out.println("[ServiceConfig] Loaded for environment: " + CURRENT_ENV);
49 }
50
51 // Private constructor — this class should never be instantiated
52 private ServiceConfig() {}
53
54 // Static accessor methods — the public API
55 public static Environment getCurrentEnvironment() { return CURRENT_ENV; }
56 public static String getServiceName() { return SERVICE_NAME; }
57 public static String getBaseApiUrl() { return BASE_API_URL; }
58 public static int getRequestTimeoutMs() { return REQUEST_TIMEOUT_MS; }
59 public static int getMaxRetryCount() { return MAX_RETRY_COUNT; }
60
61 public static boolean isFeatureEnabled(String featureKey) {
62 return "true".equalsIgnoreCase(FEATURE_FLAGS.getOrDefault(featureKey, "false"));
63 }
64
65 public static void printConfig() {
66 System.out.println("=== Service Configuration ===");
67 System.out.println("Service : " + SERVICE_NAME);
68 System.out.println("Environment : " + CURRENT_ENV);
69 System.out.println("API URL : " + BASE_API_URL);
70 System.out.println("Timeout : " + REQUEST_TIMEOUT_MS + "ms");
71 System.out.println("Max retries : " + MAX_RETRY_COUNT);
72 System.out.println("UPI enabled : " + isFeatureEnabled("upi_enabled"));
73 System.out.println("BNPL enabled: " + isFeatureEnabled("bnpl_enabled"));
74 }
75}1// File: PaymentProcessor.java
2
3public class PaymentProcessor {
4
5 private final String processorId;
6
7 public PaymentProcessor(String processorId) {
8 this.processorId = processorId;
9 }
10
11 public void processPayment(String orderId, double amount) {
12
13 // Reads shared static config — no config object passed around
14 System.out.println("[" + processorId + "] Sending to: "
15 + ServiceConfig.getBaseApiUrl());
16 System.out.println("[" + processorId + "] Processing Rs." + amount
17 + " for order " + orderId
18 + " (timeout: " + ServiceConfig.getRequestTimeoutMs() + "ms)");
19
20 if (!ServiceConfig.isFeatureEnabled("upi_enabled")) {
21 System.out.println("[" + processorId + "] UPI not enabled in this environment.");
22 }
23 }
24}1// File: ConfigDemo.java
2
3public class ConfigDemo {
4
5 public static void main(String[] args) {
6
7 ServiceConfig.printConfig();
8
9 System.out.println();
10
11 // Multiple processors share the same static config — no duplication
12 PaymentProcessor processor1 = new PaymentProcessor("PROC-A");
13 PaymentProcessor processor2 = new PaymentProcessor("PROC-B");
14
15 processor1.processPayment("ORD-1001", 1499.0);
16 System.out.println();
17 processor2.processPayment("ORD-1002", 749.0);
18 }
19}Output:
[ServiceConfig] Loaded for environment: DEVELOPMENT
=== Service Configuration ===
Service : payment-service
Environment : DEVELOPMENT
API URL : http://localhost:8080/mock/v1
Timeout : 30000ms
Max retries : 1
UPI enabled : true
BNPL enabled: false
[PROC-A] Sending to: http://localhost:8080/mock/v1
[PROC-A] Processing Rs.1499.0 for order ORD-1001 (timeout: 30000ms)
[PROC-B] Sending to: http://localhost:8080/mock/v1
[PROC-B] Processing Rs.749.0 for order ORD-1002 (timeout: 30000ms)
The static block runs once — the "[ServiceConfig] Loaded" message appears exactly once even though two PaymentProcessor objects both use the config. Every processor reads the same static fields — no configuration is passed through constructors or method arguments. Teams consistently use this pattern for application-level configuration that is environment-specific but consistent within a single JVM run.
Best Practices
Make all static fields final for constants
Mutable static fields are shared across every thread — any modification from one thread is visible to all others. This is a concurrency hazard. If a static field represents a constant that never changes after initialisation, declare it final. If it must be mutable, synchronise all access to it.
Use static for utility methods — never for methods that need object state
The correct signal that a method should be static is when it does not use any instance field. If a method works entirely from its parameters and returns a value, it belongs in a utility class as a static method. If it reads or modifies this.someField, it is an instance method.
Use a private constructor on utility classes
A utility class full of static methods should never be instantiated. Declaring a private constructor prevents both accidental instantiation and IDE-generated constructor calls. This is the pattern used by Math, Arrays, Collections, and Objects in the Java standard library.
Prefer static imports sparingly
import static java.lang.Math.sqrt lets you write sqrt(x) instead of Math.sqrt(x). Use it when a static method or constant is used frequently in one file. Avoid it when it makes the origin of names unclear — a reader should always be able to tell which class a method comes from without IDE support.
Common Mistakes
Mistake 1 — Using a Static Field for Per-Object Data
1// Wrong — every CartItem shares the same productName
2public class CartItem {
3 public static String productName; // should be an instance field
4 public static int quantity; // should be an instance field
5}
6
7CartItem item1 = new CartItem();
8item1.productName = "Laptop";
9
10CartItem item2 = new CartItem();
11item2.productName = "Mouse"; // overwrites item1's productName — same static field
12
13System.out.println(item1.productName); // prints "Mouse" — not "Laptop"Static fields model class-level data. Per-object data must be instance fields. This mistake causes all objects of the class to share one value, making the last assignment visible through every reference.
Mistake 2 — Accessing Instance Members from a Static Method
1public class OrderService {
2
3 private String serviceId = "ORDER-SVC"; // instance field
4
5 public static void processOrder(String orderId) {
6 // System.out.println(serviceId); // compile error — cannot access instance field
7 System.out.println("Processing: " + orderId); // only parameter/static access allowed
8 }
9}Static methods have no this — they cannot reference instance fields or call instance methods without an object. If the method needs instance state, it should not be static, or it should receive the object as a parameter.
Mistake 3 — Calling a Static Method on an Object Reference
1AppConfig config = new AppConfig("PRODUCTION");
2
3// Works but misleads readers — looks like an instance method call
4String name = config.APP_NAME; // IntelliJ warns: "Static member accessed via instance reference"
5
6// Correct — makes the class-level nature of the access obvious
7String name2 = AppConfig.APP_NAME;Calling static methods or accessing static fields through an object reference compiles and runs correctly but is consistently flagged as a code smell. It obscures the fact that no object state is involved and misleads readers into thinking the result depends on the specific object.
Mistake 4 — Forgetting that static Methods Cannot Be Overridden
1public class Parent {
2 public static void display() {
3 System.out.println("Parent static display");
4 }
5}
6
7public class Child extends Parent {
8 public static void display() { // this HIDES Parent.display(), does not override it
9 System.out.println("Child static display");
10 }
11}
12
13public class HidingDemo {
14 public static void main(String[] args) {
15 Parent ref = new Child(); // reference type is Parent
16 ref.display(); // prints "Parent static display" — static binding
17 // If display() were an instance method, it would print "Child static display"
18 }
19}Static methods use static binding — the method called is determined by the reference type at compile time, not the actual object type at runtime. This is called method hiding, not overriding. Polymorphism does not apply to static methods.
Interview Questions
Q1. What does the static keyword mean in Java?
static means the member belongs to the class rather than to any specific object. A static field has one copy shared by all instances. A static method can be called on the class name without creating an object. A static block runs once when the class is loaded. Static members are stored in the Method Area of JVM memory, not on the heap where objects live.
Q2. What is the difference between a static method and an instance method in Java?
A static method belongs to the class — it is called on the class name, cannot access instance fields or use this, and is resolved at compile time (static binding). An instance method belongs to a specific object — it is called on an object reference, can access both instance and static fields, uses this, and is resolved at runtime (dynamic binding). Static methods cannot be overridden — they can only be hidden in subclasses.
Q3. Can a static method access instance variables in Java?
No, not directly. A static method has no this reference — it does not belong to any specific object, so it has no access to instance fields without an explicit object reference. If a static method needs instance data, it must receive an object of the class as a parameter and access the fields through that reference.
Q4. What is a static block and when does it run?
A static block is a code block declared with the static keyword inside a class body. It runs once when the class is first loaded by the JVM — before any constructor runs and before any static field is accessed for the first time. It is used for complex initialisation logic that cannot be expressed in a single field declaration, such as loading configuration, populating a map, or performing validation. Multiple static blocks in a class run in source order.
Q5. What is the difference between a static nested class and an inner class?
A static nested class is declared with static inside another class. It can be instantiated without an instance of the outer class, and it has no implicit reference to the outer class. An inner class (non-static nested class) requires an instance of the outer class to exist, holds an implicit reference to it, and can access the outer class's instance members. Static nested classes are used for the builder pattern and self-contained helper types. Inner classes are used when tight coupling to the outer instance is needed.
Q6. Why can static methods not be overridden in Java?
Overriding requires dynamic dispatch — the JVM determines at runtime which method to call based on the actual object type. Static methods are resolved at compile time based on the reference type — this is called static binding. Because no object is needed to call a static method, there is no runtime type to dispatch on. When a subclass declares a static method with the same signature as a parent's static method, it hides rather than overrides it. Calling through a parent-type reference always invokes the parent's version.
FAQs
What is the static keyword used for in Java?
static marks a member as belonging to the class rather than to object instances. Static fields are shared across all objects. Static methods can be called without an object. Static blocks initialise class-level state once at load time. Static nested classes can be created without an outer class instance.
Can you override a static method in Java?
No. Static methods cannot be overridden — they can only be hidden. A subclass can declare a static method with the same signature, but it hides the parent's method rather than overriding it. Polymorphism does not apply — the method called is determined by the reference type at compile time, not the object type at runtime.
What is the difference between static and final in Java?
static means the member belongs to the class, not to objects. final means the value cannot be changed after assignment. They are independent and can be combined — public static final double PI = 3.14159 is a constant that belongs to the class and cannot be modified. A static field can be mutable. A final field can be per-object. Together they define an immutable class-level constant.
Can a constructor be static in Java?
No. Constructors cannot be marked static. A constructor's purpose is to initialise a new object, and static means "no object required." The two concepts are inherently contradictory. What looks like a static alternative to a constructor is a static factory method — a static method that creates and returns an object.
What happens if you modify a static field from multiple threads?
A mutable static field is shared state accessible by every thread. Without synchronisation, concurrent modifications can cause race conditions — lost updates, stale reads, and inconsistent state. Use synchronized, AtomicInteger, AtomicReference, or volatile when a mutable static field is accessed from multiple threads.
When should I use a static method instead of an instance method?
Use a static method when the operation does not depend on any instance state — when it works entirely from its parameters and produces a result without reading or modifying this.field. Utility methods, factory methods, and pure functions are good candidates. If the method ever reads an instance field, it should be an instance method.
Summary
static marks a member as belonging to the class — one copy, shared by all, accessible without an object. Static fields store class-level state like counters and constants. Static methods provide stateless utilities, factory methods, and helper operations. Static blocks handle complex one-time initialisation at class load time. Static nested classes provide logically grouped helper types, especially for the builder pattern.
The most important discipline: reach for static only when the member genuinely belongs to the class concept rather than to individual objects. Mutable static fields accessed from multiple threads require synchronisation. Static methods that cannot be overridden break polymorphism — use instance methods when inheritance and overriding matter.
For interviews, be ready to explain the static vs instance distinction with concrete memory implications, demonstrate why static methods cannot be overridden, and show how static fields combined with static blocks implement a configuration or registry pattern. These points are tested consistently across service-based definition questions and product-based design discussions.
What to Read Next
| Topic | Link |
|---|---|
| How the final keyword makes fields, methods, and classes immutable or non-extendable | Java final Keyword → |
| How the this keyword references the current object inside instance methods | Java this Keyword → |
| How encapsulation uses private instance fields to protect per-object state | Java Encapsulation → |
| How classes and objects use static and instance members together | Java Classes and Objects → |
| How inheritance interacts with static method hiding versus instance method overriding | Java Inheritance → |