Code block used to run arbitrary code during class or instance initialization.
Static and Instance initializers (sometimes called initializer
blocks) are used to run arbitrary code during initialization of a
type or object. They both can be located directly within a class
,
normal interface
, or enum
.
Initializer Blocks have the following forms:
1 | static { statements } |
2 | { statements
} |
where...
statements | is a sequence of statements, (just like in the body of any other code block). The statements can be separated by whitespace. (For more details, see blocks.) |
1 A static initializer.
2 An instance initializer.
Initializers are used to run arbitrary code during initialization of a
class or object. They provide a means of executing statements and
expressions beyond what can be executed through the variable
initializer of a static
or instance field. An initializer
executes its body statements from top
to bottom, in order, just like a normal code block.
The variable initializers in instance field declarations and the instance initializer blocks, contained within a type, collectively make up the initialization code that gets executed when an instance of that type is created. (See the Instance Initializer Code example below for details.) Similarly, the variable initializers of static fields and the static initializer blocks collectively make up the initialization code that is executed when the type is loaded. (See the Static Initializer Code example below for details.) In either case, initialization code is always executed in the same textual order as it is written throughout the class. Thereby, it is said that such initialization code is ordered. Note that other code contained within a type, (e.g. methods, constructors, inner types), is not subject to initialization code ordering.
Initializer code is executed in the order of its textual appearance. For example, consider the following class:public class Test {
int x = 10;
{
System.out.println("x's initial value: " + x);// Prints 10.
}
int y = x++; // Sets y to 10 and increments x to 11.
{
System.out.println("x's new value: " + x); // Prints 11. The change inside y's variable initializer above is reflected.
System.out.println("y's value: " + y); // Prints 10.
}
}
If a new Test();
object is created, the above code will
print the following:
x's initial value: 10
x's new value: 11
y's value: 10
Both static
and instance initializers are permitted only
in the body of a type. static
initializers may be present
in any static
class or in an enum
(which is
implicitly static
). Specifically, static
initializers may be present in:
static
classes,enum
s, after the enum
constant header.
Instance initializers may be placed in any class
body,
(including inner, local, and anonymous classes), or in enum
s
after the enum
constant header.
Both static
and instance initializers are disallowed from
referencing a field if the following are true:
static
or instance), and
x
.
A simple name is:
static
fields, the field's unqualified name
(e.g. x
instead of ClassName.x
).
x
)
or the latter accessed directly through this
, (e.g. this.x
).
This disallows initializers from directly referring to fields in a forward-reference fashion.
final
Fields
There are additional constraints that apply to both types of
initializers and their respective types of fields if the fields are
marked final
, regarding...
final
Fields
static
final
field be assigned to exactly once through any
branch of execution.This allows a static
final
variable to be declared without being given a value in
the declaration, but rather to be given a value further in the type
in a static
initializer block. E.g.: class X {
static final int someNumb;
static final String str = "Some String";
static final Map<String, Integer> myMap = new HashMap<>();
X() { }
static {
myMap.put(str, str.hashCode()); // Put something into the map.
someNumb = myMap.hashCode(); // Finally, initialize someNumb.
}
}
final
instance field be assigned to, exactly once, through any branch of
execution, including through code executed in any constructor. Initialization of any final
instance field must be done either through the constructors of a
class or the class's intialization code (field declarations and
instance initializer blocks). It cannot be through both, otherwise a
compile-time error results, and it must be done through one so that
the field is initialized by the time construction completes.
Such initialization must be performed through simple reference;
it is always a compile-time error to attempt to assign to a final
field other than through a simple reference.
final
Fields
It is a compile time error if an initializer block attempts to refer to
a final
field through simple reference, before its
initialization, unless that reference is as the left-hand side of an
assignment. final
fields must be initialized (via simple
reference) before they can be referenced in ways other than assignment
(by simple reference).
static
Initializers
static
initializers may not directly refer to instance
members, as there is no implicitly accessible state available for static
code. References to instance members must be qualified with an
expression.
public class Dog {
String q = "ABC"; // "Conventional" initialization code: give field a value.
{
System.out.println("First Statement");
System.out.println("Second Statement");
}
}
Simply creating a new Dog();
will cause the initializer
block to run, resulting in the output:
First Statement
Second Statement
class Test {
{
System.out.println("Point 1: " + ((Test) this).x); // At this point, x has not been declared, and so has value 0.
// x++; // x is not yet declared.
// this.x++; // x is not yet declared.
((Test) this).x++; // x is now 1.
System.out.println("Point 2: " + ((Test) this).x);
}
int x = 5; // x is set to 5.
{
System.out.println("Point 3: " + x);
// Increment x 3 times:
x++;
this.x++;
((Test) this).x++; // x is now 8
System.out.println("Point 4: " + x);
}
}
This code prints the following:
Point 1: 0
Point 2: 1
Point 3: 5
Point 4: 8
static
and Instance Initializers
Instance initializer code can access static
fields:
public class Example {
static int count;
String str;
{
str = "Item #" + count++;
}
public static void main(String[] args) {
System.out.println(new Example().str); // Create one example object.
System.out.println(new Example().str); // Create another.
System.out.println(new Example().str);
Example nextExample = new Example(), lastExample = new Example();
System.out.println();
System.out.println("Last two Example objects:");
System.out.println(nextExample.str);
System.out.println(lastExample.str);
}
}
Output:
Item #0
Item #1
Item #2
Last two Example objects:
Item #3
Item #4
public class C {
static {
System.out.println("Initializer 1 (Static)");
}
{
System.out.println("Initializer 2 (Instance)");
}
C() {
System.out.println("Constructor");
}
static {
System.out.println("Initializer 3 (Static)");
}
{
System.out.println("Initializer 4 (Instance)");
}
public static void main(String[] args) {
System.out.println("Main method started.");
new C();
}
}
Output:
Initializer 1 (Static)
Initializer 3 (Static)
Main method started.
Initializer 2 (Instance)
Initializer 4 (Instance)
Constructor
final
instance field
without initializer blocks or a constructor, even when that field is
declared without a variable initializer: public class InitializerTest {
final int x;
final int y;
final int z;
final double test = x = y = z = 10;
}
In this example, the three int
variables are each set to
10
and the variable test
is set to 10.0
.
This is also possible for static
fields.
public class InitializerTest {
static final int x;
static final int y;
static final int z;
static final double test = x = y = z = 10;
}
public class Test {
static final int x = Test.y;
static final int y = Test.x;
}
As with other fields, the default value of y
, (which is
what Test.y
evaluates to in x
's variable
initializer), is 0
, so both x
and y
are initialized to the value 0
.
static
initializer code completes, particularly in the
case that static
initializer code attempts to create an
object of the class currently being initialized: class Test {
// Instance initializer code
{
System.out.println(x);
}
// Static initializer code
static int x;
static {
new Test(); // Create new Test before static initialization has completed. This causes the instance initializer to be run.
// The object instantiation prints 0, since x has not been assigned to yet.
x = 10000;
}
}
Output:
0
main(String[])
method begins by including such code in a static
initializer block in the class containing the main(String[])
method: public class Test {
private static int x;
static {
Scanner s = new Scanner(System.in);
System.out.print("Please enter a number: ");
x = s.nextInt();
}
public static void main(String[] args) {
System.out.println("You entered " + x + " before the main method was called.");
}
}
Calling this code and providing the command-line input:
14
will print the output:
You entered 14 before the main method was called.
static
initializer inside
an interface
(including @interface
s)
indirectly, by declaring a class
or enum
within the interface and including the static
initializer
inside that.