Concepts / Static Variables and Static Initialization

Static Variables and Static Initialization

An instance variable can receive an initial value directly in its declaration, such as public int die1 = 3;, and that value is the starting value of each new object.

  • Programming

Why Starting Values Matter

Every object you create begins its life with some values stored in its fields. Consider a program that models a pair of dice. Each pair needs two numbers, one for each die, and those numbers must already have a value the moment the pair exists. Someone reading the class has to know what those starting values are, and so does anyone debugging a program that seems to show the wrong number. In this article we follow one class from its source code through to the values an object actually holds, and we look at where those values come from.

What do you think happens?

A class declares public int count; and gives it no initializer. What value does a new object start with in count?

  • 0

  • 1

  • No value at all, so reading it causes an error

Reveal answer
Answer:

0

When a declaration has no initializer, Java supplies a default. Numeric types such as int start at zero.

Tracing a New PairOfDice Object

The answer comes straight from the declarations. Here is a small class that models a pair of dice. Each die is an instance variable of type int, and each declaration includes an initializer after the equals sign. The roll() method is the only code in this class that changes the dice, and it runs only when someone calls it. The assignments inside roll() are example code written for this article.

java

When new PairOfDice() runs, the object is created with die1 holding 3 and die2 holding 4. Nothing else has to happen first. The values are already in place before any method is called. The diagram below shows the fields inside that new object. Its nodes are the two instance variables and the object that holds them.

PairOfDice objectdie13die24fieldfield
After new PairOfDice() runs, what value does each instance variable hold, and where does that value live inside the object?

The two fields are part of the object, so they exist for as long as the object does. Their starting values are fixed by the declarations, not by the constructor or by any method. A reader of the class can therefore see the starting state of each field without searching through other code.

How an Initializer Sets the Starting Value

Definition

An explicit initializer is the value written after the equals sign in an instance variable declaration. The field holds that value when each new object is created.

An instance variable can receive an initial value in its declaration, in the same way any other variable can. You write the type, the name, an equals sign, and the starting value. The statement public int die1 = 3; declares an instance variable named die1 that holds an int, and it fixes that variable's starting value at 3.

An initializer is not a one-time setup for the whole class. Every time a new PairOfDice is created, the dice are set to their starting values. Because the initialization runs for each new object, each pair gets its own copy of the instance variables, and different pairs can hold different values. If an initializer computed random numbers, every new pair would receive a fresh set of random starting values.

The before version has no initializers, so Java gives each int field the default zero. The after version has initializers, so the same two fields start at 3 and 4. The fields have the same names and the same type. Only the starting value differs, and the initializer is what makes the difference.

Default Values by Type

A declaration does not have to include an initializer. If you leave one out, Java still gives the instance variable a starting value automatically, and the value depends on the variable's type. The table lists the rules for the four kinds of field covered in the source.

Field typeDefault starting valueNotes
Numeric types such as int and double0The zero of that numeric type
booleanfalseNot written as a string
charThe Unicode character with code number zeroCast to int to see its numeric code
Object types, including StringnullA String field is null, not an empty string

Default starting values Java assigns to instance variables with no initializer

The object-type row deserves attention. String is an object type, so a String field with no initializer begins as null. It does not begin as an empty string, which is a different value that a program must write explicitly.

Initializerwritten?Starting value is theinitializerStarting value is thetype defaultyesno
Given a field declaration, does its starting value come from an initializer or from Java's default?

Worked Example: Reading Default Values

The next program declares four fields with no initializers and prints the value each one holds. Casting the char to int is a way to show its numeric code, since a raw zero character would be hard to read on screen.

java
Output
0
false
0
null
Notes on the code
  • count has no initializer, so it holds the int default 0
  • flag has no initializer, so it holds the boolean default false
  • letter holds the char with code number zero, and casting to int prints that code as 0
  • name is a String, an object type, so it holds null rather than an empty string
Worked example

Predicting Four Printed Lines

Before running DefaultDemo, predict the four lines it prints, one for each field.

  1. 1
    Check count

    The declaration int count; has no initializer. The type is numeric, so the default is 0.

  2. 2
    Check flag

    The declaration boolean flag; has no initializer. The type is boolean, so the default is false.

  3. 3
    Check letter

    The declaration char letter; has no initializer. The default is the character with code number zero. Casting it to int prints 0.

  4. 4
    Check name

    The declaration String name; has no initializer. String is an object type, so the default is null.

Result

The program prints 0, false, 0, and null, in that order.

The example separates two moments that are easy to confuse: the moment an object begins and the moment its values change. Initialization belongs to the first moment, and assignments inside methods belong to the second. In DefaultDemo nothing assigns a value after creation, so the printed lines show the starting state alone.

Static Initialization Happens Once

Everything above concerns instance variables, which belong to each object. Static member variables follow a different pattern. There is only one copy of a static variable, so its initialization is executed just once, when the class is first loaded. Instance variable initialization repeats with every object, while static initialization happens once for the class as a whole.

Mistakes With Starting Values

  • Common mistake

    Assuming a String field with no initializer is an empty string

    What it looks like
    String name; followed by name.length() when no value has been assigned
    Why it fails

    A String is an object type, so its default is null, not an empty string.

    Do this instead

    Assign a value explicitly, such as name = "", if an empty string is what the program needs.

  • Common mistake

    Assuming a field with no initializer holds some unpredictable value

    What it looks like
    int count; with no initializer, expecting the printed result to be a leftover number
    Why it fails

    Java supplies a defined default for every instance variable with no initializer, and for int that default is 0.

    Do this instead

    Check the declaration for an initializer and the type's default rule before looking for other causes.

  • Common mistake

    Blaming the initializer when a later assignment changed the value

    What it looks like
    die1 = 3 in the declaration, but roll() has already changed die1 before the program prints it
    Why it fails

    The initializer sets the starting value only. Assignments made later, inside methods, change the value afterward.

    Do this instead

    Ask which moment produced the value: object creation, or a later assignment. Trace the assignments that ran before the read.

Locating an Unexpected Starting Value

EASY

A class declares public int die1 = 3; and public int die2; with no initializer. A program creates a new object and immediately prints die2. Without running the code, what value is printed, and which declaration explains it? Then explain what you would check first if the printed value were not what you predicted.

Hints
  • Check each field declaration for an initializer after the equals sign.
  • A numeric field with no initializer starts at the default for its type.
  • If a field has an initializer but still shows a different value, look for an assignment that ran before the read.

Key Takeaways

  • An explicit initializer, such as public int die1 = 3;, sets the starting value that each new object receives in that field.
  • When a declaration has no initializer, Java supplies a default: zero for numeric types, false for boolean, the zero-code character for char, and null for object types including String.
  • Instance variable initialization runs for every new object, so each object gets its own values, while static variables are initialized once when the class is first loaded.
  • When a starting value looks wrong, check whether the declaration has an initializer, then check whether later code assigned a different value before the value was read.