Java Order of Initialization and Instantiation

Java order of Initialization and Instantiation

It is important to distinguish between the initialization of a class, and initialization of an object.

Class Initialization

A class or interface is initialized upon first access, by assigning the compile time constant fields, then recursively initializing the superclass (if not already initialized), then processing the static initializers (which include the initializers for for the static fields that are not compile time constants).

As you have noticed, initialization of a class does not, by itself, trigger initialization of the interfaces it implements. Interfaces are therefore initialized when they are first accessed, typically by reading a field that is not a compile time constant. This access may occur during evaluation of an initializer, causing a recursive initialization.

It is also worth noting that initialization is not triggered by accessing fields that are compile time constants, as these are evaluated at compile time:

A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.

If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed.

If such a field is non-static, then no reference to the field should be present in the code in a binary file, except in the class containing the field. (It will be a class rather than an interface, since an interface has only static fields.) The class should have code to set the field's value to V during instance creation (§12.5).

Object Initialization

An object is initialized whenever a new object is created, typically by evaluation of a class instance creation expression. This proceeds as follows:

  1. Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.

  2. If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then evaluate the arguments and process that constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason; otherwise, continue with step 5.

  3. This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If this constructor is for a class other than Object, then this constructor will begin with an explicit or implicit invocation of a superclass constructor (using super). Evaluate the arguments and process that superclass constructor invocation recursively using these same five steps. If that constructor invocation completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, continue with step 4.

  4. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.

  5. Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly for the same reason. Otherwise, this procedure completes normally.

As we can see in step 3, the presence of an explicit call to the super constructor simply changes which super class constructor is invoked.

In Java, what is the order of initialization for those statements after main method

1) Block that does not have name like below is called "Instance Initializer" which only get called when new objects will be created its like DefaultConstructor or noArg Constructor.

{
add(11);
}

2) In above code you have Static Block (Which get called first at the Class Loading itself), Instance Initializer (Which get called while creating the object), Explicit DefaultConstructor (Which get called while creating the object but remember always Instance initializer takes priority) and last Main method.

3) Now lets analyze your code,

1st call:

static 
{
add(2); //print 2
}

2nd call:

static {
add(4); // print 4
}

3rd call:

static {
new Test1();
// Here Object is getting created so all Instance Initialzer will be called first in a sequential manner.
}

4th call:

{
add(6); // print 6
}

5th call:

{
add(8); // print 8
}

6th call:

{
add(11); // print 11
}

7th call : After Instance Initializer, Explicit Default Constructor will be called.

public Test1() {
add(5); // print 5
System.out.println("Constructor!"); // print Constructor!
}

8th call: Again the last Static block will be called.

static {
add(12); // print 12
}

9th call: Finally the main method will be called

public static void main(String[] args) {
System.out.println("Main method!"); // print Main method!
add(10); // print 10
}

Are the member fields in a Java class initialized in order of declaration?

Yes, it's guaranteed.

In particular, JLS 12.5 Creation of New Class Instances says (emphasis added):


  1. Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class. If execution of any of these initializers results in an exception, then no further initializers are processed and this procedure completes abruptly with that same exception. Otherwise, continue with step 5.

When does the members of the class initialize?

You can analyze the question this way:

class Scratch {
public static void main(String[] args) {
A a = new A ("xyz");
}
}

class A{
public B b = new B();
private C c = new C(123);

public A (String a){
System.out.println("new A()");
}
}

class B {
public B() {
System.out.println("new B()");
}
}

class C {
public C(int i) {
System.out.println("new C()");
}
}

which executes giving the following output:

new B()
new C()
new A()

which matches wiith the answer of @Jakir Hossain.

So: inline fields initializers are executed before code in constructor, following the same order which they are declared in.

Instances of classes B and C are created on A's instance creation, before A's constructor is executed. This ordering (and fields' initialization) are guaranteed.

Initialization order of nested classes

I've read much about initialization but still haven't come across in what order inner classes are initialized.

Class initialization is about the initialization of a classes static fields and execution of static initializer blocks. However, an inner class in Java is not allowed to have any static fields or static initializers. (See JLS 8.1.3.) Hence (real) class initialization for inner classes is moot. It makes no difference when it happens ... 'cos there is nothing in an inner class to initialize.

The real problem here is that while you have a static field, its actual initialization (to a non-null value) is not done during static initialization. Rather, it would happen when some part of your code explicitly calls BaseClass.main(). However, none of your code does that ... and hence myClass is going to be null when you try to use it.

Again ... I stress ... this is not an issue of how static initialization works, because your code doesn't use static initialization to initialize the field in question.

In what order do static/instance initializer blocks in Java run?

The static initializer for a class gets run when the class is first accessed, either to create an instance, or to access a static method or field.

So, for multiple classes, this totally depends on the code that's run to cause those classes to get loaded.

final variable initialized first

The order of initialization doesn't change the fact that the JLS doesn't let you refer to variables before they're declared in various cases. This is described in JLS§8.3.3:

Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:

  • The declaration of a class variable in a class or interface C appears textually after a use of the class variable;

  • The use is a simple name in either a class variable initializer of C or a static initializer of C;

  • The use is not on the left hand side of an assignment;

  • C is the innermost class or interface enclosing the use.

That's why your code gets this compilation erorr:

error: illegal forward reference

The statement that static fields that are constant variables are initialized first is indeed defined in JLS§12.4.2:


  1. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.

    Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).


...


  1. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

As you can see, constant variables are initialized in step 6, but others in step 9.

This demonstrates the behavior:

public class Example {
static String y;
static {
y = foo();
}

static String foo() {
return x.toUpperCase();
}

public static final String x = "test";

public static void main(String[] args) throws Exception {
System.out.println(x);
System.out.println(y);
}
}

That compiles, and outputs:


test
TEST

In contast, if you change the x line so it's not constant anymore:

public static final String x = Math.random() < 0.5 ? "test" : "ing";

It compiles, but then fails because x is null as of y = foo();.


For the avoidance of doubt: I don't recommend using methods to initialize fields like that. :-)



Related Topics



Leave a reply



Submit