static Keyword

Su Suriya Ravichandran Updated 14 Nov 2026
8 min read ·Lesson 48 of 133

The static keyword marks a member as belonging to the class itself rather than to individual objects. A static field has one copy shared by the whole program; a static method can be called without creating any object. static can be applied to fields, methods, initializer blocks, nested classes, and imports. Knowing when something should be static, and when it must not be, is a core design skill.

Instance Members Versus Static Members

public class Visitor {
    private static int totalVisitors = 0;    // one copy, shared by all Visitor objects
    private final String name;               // one copy per object

    public Visitor(String name) {
        this.name = name;
        totalVisitors++;
    }

    public String getName() { return name; }
    public static int getTotalVisitors() { return totalVisitors; }
}
new Visitor("Ada");
new Visitor("Linus");
new Visitor("Grace");

System.out.println(Visitor.getTotalVisitors());   // 3
Class Visitor (loaded once)
┌──────────────────────────┐
│ static totalVisitors = 3 │◄──── shared by all instances
└──────────────────────────┘
 Objects:
 ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
 │ name="Ada"   │ │ name="Linus" │ │ name="Grace" │
 └──────────────┘ └──────────────┘ └──────────────┘

Each Visitor has its own name. There is a single totalVisitors, stored with the class, and every constructor call increments the same variable.

Instance memberStatic member
Belongs toEach objectThe class
CopiesOne per objectOne in total
Accessed viaAn object reference: v.getName()The class name: Visitor.getTotalVisitors()
Exists whenThe object is createdThe class is loaded
Can use thisYesNo

Static Fields

A static field holds data shared by every instance, or data that belongs to the type rather than to any object.

Shared counters and state

public class Ticket {
    private static int nextId = 1;
    private final int id;

    public Ticket() {
        this.id = nextId++;
    }

    public int getId() { return id; }
}
Ticket a = new Ticket();
Ticket b = new Ticket();
System.out.println(a.getId() + ", " + b.getId());   // 1, 2

Each ticket receives a unique ID from the shared counter. (In multithreaded code this counter would need synchronization or an AtomicInteger, because two threads could read the same value; this is covered in the multithreading section.)

Constants: static final

The most common static fields are constants: values that never change and belong to the class.

public class Tax {
    public static final double GST_RATE = 0.18;
    public static final int MAX_LINE_ITEMS = 100;
    public static final String CURRENCY = "INR";
}

double gst = amount * Tax.GST_RATE;

static provides one shared copy; final prevents reassignment. Constants are named in UPPER_SNAKE_CASE. Math.PI, Integer.MAX_VALUE, and System.out are static fields of JDK classes.

For a static final field holding a mutable object, final only protects the reference:

public static final List<String> ROLES = new ArrayList<>();
ROLES.add("hacker");       // allowed: the list itself is mutable

public static final List<String> ROLES = List.of("ADMIN", "EDITOR", "VIEWER");   // truly constant

Use immutable collections for constants that are collections.

Static Methods

A static method does not operate on an object. It is called using the class name:

public class Validators {
    public static boolean isValidPin(String pin) {
        return pin != null && pin.matches("\\d{6}");
    }

    public static boolean isValidPhone(String phone) {
        return phone != null && phone.matches("[6-9]\\d{9}");
    }
}

if (Validators.isValidPin("600042")) { ... }

Typical uses:

UseExamples
Pure functions of their argumentsMath.sqrt, Integer.parseInt, String.valueOf
Factory methodsList.of, LocalDate.of, Path.of, Optional.empty
Utility classesArrays, Collections, Objects, Files
Program entry pointpublic static void main(String[] args)

main is static because the JVM must call it before any object of your class exists.

Restrictions

A static method has no current object, so it cannot directly access instance fields, call instance methods, or use this:

public class Counter {
    private int count;

    public static void main(String[] args) {
        count++;                 // compile error: non-static variable count cannot be
                                 // referenced from a static context
        increment();             // compile error: non-static method
        Counter c = new Counter();
        c.count++;               // fine: accessed through a specific object
    }

    void increment() { count++; }
}

The reverse is always allowed: instance methods can read static fields and call static methods freely, since the class's static members are available everywhere in the class.

Static methods cannot be overridden

Static methods are resolved at compile time from the declared type, not at runtime from the object. A subclass that declares a static method with the same signature hides the parent's method rather than overriding it:

class Parent { static String who() { return "parent"; } }
class Child extends Parent { static String who() { return "child"; } }

Parent p = new Child();
System.out.println(p.who());       // "parent": decided by the declared type

Calling a static method through an instance reference compiles (with a warning) but is misleading for exactly this reason. Always call static methods through the class name: Parent.who().

Static Initializer Blocks

A static block runs once, when the class is first loaded, and is used for static setup that does not fit in a single expression:

import java.util.HashMap;
import java.util.Map;

public class CountryCodes {
    private static final Map<String, String> CODES;

    static {
        Map<String, String> m = new HashMap<>();
        m.put("IN", "India");
        m.put("US", "United States");
        m.put("JP", "Japan");
        CODES = Map.copyOf(m);         // store an unmodifiable copy
        System.out.println("CountryCodes loaded");
    }

    public static String name(String code) {
        return CODES.getOrDefault(code, "Unknown");
    }
}
System.out.println(CountryCodes.name("IN"));
System.out.println(CountryCodes.name("JP"));

Output:

CountryCodes loaded
India
Japan

The message prints once, before the first use of the class. The class is initialized lazily: if a program never uses CountryCodes, its static block never runs. Static fields and blocks are processed in the order they appear in the source.

If a static initializer throws an exception, the class fails to initialize and every later attempt to use it throws NoClassDefFoundError (after an initial ExceptionInInitializerError). Keep static initialization simple and unlikely to fail.

Static Nested Classes

A class declared inside another with static is a static nested class. It does not hold a reference to an instance of the outer class, so it can be created on its own:

public class Order {
    private final List<Line> lines = new ArrayList<>();

    public static class Line {
        private final String product;
        private final int qty;

        public Line(String product, int qty) {
            this.product = product;
            this.qty = qty;
        }
    }

    public void add(Line line) { lines.add(line); }
}

Order.Line line = new Order.Line("Pen", 3);   // no Order object needed

Use a static nested class when the nested type is closely related to the outer one but does not need access to a particular outer instance; builders and small helper types are typical. A non-static (inner) class keeps a hidden reference to its outer object, which uses memory and can prevent the outer object from being garbage collected. Make nested classes static unless they genuinely need the outer instance. Nested and inner classes have their own lessons.

Static Imports

import static lets you use static members without the class name:

import static java.lang.Math.PI;
import static java.lang.Math.pow;

double area = PI * pow(radius, 2);

It is most useful in tests (assertEquals, assertTrue) and for heavily used constants. Overuse makes it unclear where names come from.

When to Use static

Make a member static when:

  • It represents data shared across all instances (a counter, a cache, a configuration constant).
  • A method depends only on its parameters, not on any object's state.
  • A method creates instances (factory method).
  • A nested class does not need the outer instance.

Avoid static when:

  • The data differs from object to object. A static String name in a Student class would give every student the same name.
  • You need polymorphism. Static methods cannot be overridden, so behavior that varies by subtype must be in instance methods.
  • The state is mutable and shared. Mutable static fields are effectively global variables: any code can change them, which makes behavior depend on hidden history, causes problems in multithreaded code, and makes tests interfere with each other.
// Problematic: hidden global state
public class Cart {
    private static List<String> items = new ArrayList<>();   // every Cart shares one list!
}

// Correct: each cart owns its items
public class Cart {
    private final List<String> items = new ArrayList<>();
}

The first version is a common beginner mistake: adding an item to one customer's cart adds it to everyone's.

Utility Classes

A class containing only static members should not be instantiated. Make it final and give it a private constructor:

public final class PriceUtils {
    private PriceUtils() {}                    // prevents new PriceUtils()

    public static double withGst(double amount) {
        return amount * 1.18;
    }

    public static String format(double amount) {
        return String.format("₹%,.2f", amount);
    }
}

System.out.println(PriceUtils.format(PriceUtils.withGst(12500)));   // ₹14,750.00

java.util.Collections, java.util.Arrays, java.util.Objects, and java.lang.Math follow this pattern.

Practical Example: Configuration and Instances

import java.util.ArrayList;
import java.util.List;

public class Student {
    public static final int MAX_COURSES = 5;          // constant
    private static int enrolledCount = 0;             // shared statistic

    private final String name;                        // per-student data
    private final List<String> courses = new ArrayList<>();

    private Student(String name) {
        this.name = name;
        enrolledCount++;
    }

    public static Student register(String name) {     // static factory
        if (name == null || name.isBlank()) {
            throw new IllegalArgumentException("name required");
        }
        return new Student(name.strip());
    }

    public boolean join(String course) {               // instance behavior
        if (courses.size() >= MAX_COURSES || courses.contains(course)) {
            return false;
        }
        return courses.add(course);
    }

    public static int getEnrolledCount() {
        return enrolledCount;
    }

    @Override
    public String toString() {
        return name + " " + courses;
    }

    public static void main(String[] args) {
        Student a = Student.register("Ada");
        Student b = Student.register(" Linus ");

        a.join("Java");
        a.join("Docker");
        b.join("C");

        System.out.println(a);
        System.out.println(b);
        System.out.println("Students: " + Student.getEnrolledCount());
        System.out.println("Course limit: " + Student.MAX_COURSES);
    }
}

Output:

Ada [Java, Docker]
Linus [C]
Students: 2
Course limit: 5

MAX_COURSES is a rule that applies to every student, so it is a static constant. enrolledCount is a statistic about the class as a whole, so it is a static field updated in the constructor. name and courses differ for each student, so they are instance fields. register is a static factory because it creates students; join is an instance method because it changes one particular student's courses. Each member's placement follows directly from the question: does this belong to one student, or to students in general?

0 Comments

Reviewed before they appear

No comments yet.

Java
Java Introduction Java Features Java Syntax Java Comments Java Statements Java Output Java Variables Java Data Types Java Type Casting Java Operators Java Strings Java Numbers Java Math Java Booleans Java User Input Java Conditions Java If Else Java Switch Java While Loop Java For Loop Java Break Java Continue Java Arrays Java Methods Java Parameters Java Return Values Java Scope Java Recursion Install Java Install JDK Java IDEs Java JDK Java JRE Java JVM Java Compiler Java File Compile Java Run Java JShell Basics Java Packages Java OOP Java Classes Java Objects Class Methods Constructors Constructor Overload this Keyword static Keyword final Keyword Encapsulation Inheritance Polymorphism Abstraction Access Modifiers super Keyword Method Overload Method Override Instanceof Operator Nested Classes Inner Classes Anonymous Classes Enums Records Array Basics Array Length Loop Arrays Multidimensional Arrays Array Copy Array Sorting Array Search ArrayList LinkedList HashSet TreeSet HashMap TreeMap Queue Interface Deque Interface Stack Class Iterator List Interface Set Interface Map Interface Collections Class Comparable Comparator Generics Basics Generic Classes Generic Methods Wildcards String Basics String Length String Methods String Concatenation String Compare String Search String Replace String Split String Format StringBuilder StringBuffer Text Blocks Regular Expressions Number Types Integer Class Float Class Double Class BigInteger BigDecimal Math Class Random Numbers Number Format Date Basics LocalDate LocalTime LocalDateTime ZonedDateTime Date Formatting Date Parsing Period Class Duration Class Java Instant Class Java Exception Basics Java try...catch Java Multiple Catch Blocks Java finally Block Java throw Keyword Java throws Keyword Java Checked Exceptions Java Unchecked Exceptions Java Custom Exceptions Java try-with-resources Java Exception Chaining
Ask about this post
AI Ask about this post

Ask questions about static Keyword and get answers drawn from it.

Signed-in readers only.