Static and Final in Java: Shared State, Constants and Override Rules with Runnable Examples

Learn what static and final control in Java by tracing a shared counter, class initialisation, final references, constants and inheritance errors.

KnowledgeGate Team

Exam prep & CS education

Updated 24 Oct 20266 min read

static and final often appear together, but they solve different problems. static decides that a member belongs to the class, while final restricts reassignment, overriding or inheritance according to where it appears. Static and final govern shared state, initialisation order and compiler errors.

Static and final in Java: build the modifier map first

Start by asking two different questions: who owns this member, and what change is forbidden?

Context

static means

final means

Field

One class-level copy

Assigned once

Method

Called without an implicit object or this

Cannot be overridden

Class

Allowed for a nested class, not a top-level class

Cannot be extended

Local variable

Not allowed

Assigned once

Parameter

Not allowed

Cannot be reassigned inside the method

The modifiers are not opposites. static final int MAX_RETRIES = 3; declares one class-level value that cannot be reassigned after initialisation. A static initialiser also runs once when its class is initialised.

Static fields and methods: trace one shared counter

This program gives each support ticket its own final ticket number while one static field stores the next available number.

java
class Ticket {
    static int nextNumber = 1001;
    final int ticketNo;
    final String topic;

    Ticket(String topic) {
        this.topic = topic;
        this.ticketNo = nextNumber++;
    }

    static int issued() {
        return nextNumber - 1001;
    }

    public static void main(String[] args) {
        Ticket login = new Ticket("Login");
        Ticket billing = new Ticket("Billing");
        Ticket playback = new Ticket("Playback");
        System.out.println(login.topic + " -> " + login.ticketNo);
        System.out.println(billing.topic + " -> " + billing.ticketNo);
        System.out.println(playback.topic + " -> " + playback.ticketNo);
        System.out.println("Issued: " + Ticket.issued());
        System.out.println("Next number: " + Ticket.nextNumber);
    }
}

The first constructor stores 1001 in the login ticket's ticketNo, then raises nextNumber to 1002. The billing ticket receives 1002, the playback ticket receives 1003, and the shared field finishes at 1004. The exact output is:

Code
Login -> 1001
Billing -> 1002
Playback -> 1003
Issued: 3
Next number: 1004

There are three ticketNo fields but only one nextNumber. issued() can read that shared field, but it cannot directly read topic or use this because no particular Ticket object is attached to a static method. Class-qualified access such as Ticket.issued() makes that ownership clear. Do not make every field static merely to silence a non-static access error.

Static initialisation order: prove what runs once

The following program separates class initialisation from work performed for each object. BASE is a blank static final field assigned exactly once.

java
class Config {
    static final int BASE;
    static int runs = 1;

    static {
        BASE = 40;
        runs += 2;
        System.out.println("static block: " + runs);
    }

    {
        runs++;
        System.out.println("instance block: " + runs);
    }

    Config() {
        System.out.println("constructor: " + runs);
    }

    public static void main(String[] args) {
        new Config();
        new Config();
        System.out.println("sum: " + (BASE + runs));
    }
}

Static field initialisers and static blocks execute in source order when this class is initialised. Here, runs becomes 1 + 2 = 3 before main. The first instance block changes it to 4, then the first constructor prints 4. The second pair prints 5, and the final calculation is BASE + runs = 40 + 5 = 45.

Code
static block: 3
instance block: 4
constructor: 4
instance block: 5
constructor: 5
sum: 45

The static block runs once. For each new object here, the instance initialiser runs before the constructor body, so both run twice.

Execution timeline for Config: the static block runs once setting BASE to 40 and runs to 3, then two objects raise runs to 5 and sum to 45.

Final variables, references and static final constants

final prevents another assignment to a variable. It does not automatically make the referenced object immutable.

java
final int[] marks = {70, 80};
marks[0] = 95;
System.out.println(java.util.Arrays.toString(marks)); // [95, 80]
// marks = new int[]{60, 70}; // compile-time error

The array object can change, but marks cannot point to another array. The same distinction explains why String Handling in Java: Pool, Immutability, Interview Questions treats immutability as an object property, not a benefit automatically granted by a final reference.

An instance blank final such as ticketNo must be assigned once on every constructor path. A static blank final such as BASE may be assigned at declaration or in a static initialiser. A final parameter cannot be reassigned inside its method, although a mutable object passed through it may still change.

java
class CircleMath {
    static final double PI = 3.14159;

    static double area(double radius) {
        return PI * radius * radius;
    }

    public static void main(String[] args) {
        System.out.printf("%.2f%n", area(4));
    }
}

The calculation is area(4) = PI * 4 * 4 = 3.14159 * 16 = 50.26544, which %.2f prints as 50.27. Uppercase names are the convention for constants. A compile-time constant is narrower than every static final field: it must be a primitive or String initialised with a constant expression.

Final methods and final classes: control inheritance

A final method blocks overriding only that method. A final class blocks subclassing altogether.

java
class Report {
    final int score() { return 80; }
}

class AdvancedReport extends Report {
    // int score() { return 95; } // error: cannot override final method
}

final class AuditLog {}
// class ExtendedAuditLog extends AuditLog {} // error: cannot inherit

new AdvancedReport().score() still calls the inherited method and returns 80. An abstract final class or method is contradictory and illegal because an abstract declaration requires subclass implementation. If that inheritance vocabulary needs revision, use OOP for Teaching CS Exams: Classes and Inheritance before returning to these modifier rules.

Static and final mistakes: diagnose the compiler message

Consider static int x = 7; int y = 3; static int total() { return x + y; }. It fails because y belongs to an object. Make total() an instance method if it represents one object's state, or pass the required object explicitly. Changing y to static is correct only if the class should truly share it.

Next, final StringBuilder text = new StringBuilder("A"); text.append("B"); is legal and produces AB. Assigning a new StringBuilder to text is illegal. Again, mutation is not reassignment.

A blank final must be definitely assigned exactly once on every path. final int mode; if (args.length > 0) mode = 1; else mode = 0; is legal, but a later unconditional mode = 2; is not. Also avoid exposing a mutable collection as public static final: callers cannot replace its reference, but they can still change the shared contents.

How coding tests and interviews check static and final

Typical questions ask you to predict a shared counter, identify access from a static context, or separate final-reference mutation from reassignment. Justify each answer using ownership and assignment count.

Snippet

Result

Exact value or rule

Box.count after static int count = 2;, two objects and count += 3 per constructor

Compiles

2 + 3 + 3 = 8

final int[] values = {2, 4}; values[1] *= 3;

Compiles

values[1] = 4 * 3 = 12

static final int LIMIT = 5; System.out.println(LIMIT);

Compiles

Prints 5; reading LIMIT is legal

LIMIT++;

Fails

It attempts to reassign a final field

These patterns test the rule behind the keyword. Ask which object owns the data, how many assignments occur, and whether inheritance is attempting an override.

Static and final in Java: the short version and next practice step

  • A static field has one shared class-level copy.

  • A static method has no implicit object.

  • A final variable or reference is assigned once.

  • A final method cannot be overridden.

  • A final class cannot be extended.

static final is the usual shape for a class constant, but it does not freeze a mutable object. As a quick exercise, change Ticket.nextNumber to 5001 and issued() to return nextNumber - 5001, then create four tickets. The sequence is 5001, 5002, 5003, 5004, so the fourth ticketNo is 5004, issued() returns 5005 - 5001 = 4, and the next shared value is 5005.

For guided concept and question practice, continue with Java Course: Concepts, MCQs and Coding Questions. Use the Complete Java Course when you want a basics-to-advanced route that includes OOP and application work. If you only need to compare Java with the wider programming and DSA catalogue, browse Coding & DSA Courses for Placements.