Are Fields Initialized Before Constructor Code Is Run in Java

Do final fields initialized outside of constructors get initialized before running the constructor?

It's not possible for final fields.

Just look at The Java ® Language Specification Java SE 8 Edition > 17.5.2 Reading final Fields During Construction:

17.5.2 Reading final Fields During Construction

A read of a final field of an object within the thread that constructs that object is
ordered with respect to the initialization of that field within the constructor by the
usual happens-before rules. If the read occurs after the field is set in the constructor,
it sees the value the final field is assigned, otherwise it sees the default value.

But as you also can see it's not guarantied for subsequent final field modifications using reflection. See 17.5.3 for more details.

Why are not the fields initialized before their possible first use?

Let me paraphrase your "intuitive" order of constructing a new object:

  1. Parent's fields are initialized
  2. Child's fields are initialized
  3. Parent's constructor is called
  4. Child's constructor is called

Well, that is not really reasonable because the initialization of child's fields can be dependent on the parent.

An object can be considered "properly initialized" when its constructor returns. Agree?

Instead of using Parent and Child, let's use Box and TreasureBox. To construct a TreasureBox, you start by making a Box. After the box is created, you add different decorations to it to make it look all fancy and cool, and you might also add a lock or whatnot.

See? the order here? It makes the most sense to properly initialize the parent first, before initializing the child, which means any initialization of the child class must occur after the parent's constructor returns. This is exactly what Java is doing.

The child's fields can be dependent on the parent's fields. To put a lock on a TreasureBox, you need to find the front of the box, and put it on there. If the box's front side has not been created yet, how can you put a lock on it?

Here's some code to clarify what I mean:

class Parent {

public String parentField;

public Parent(){
parentField = "Hello";
}
}

class Child extends Parent {

public int childField = parentField.length();
}

If Java uses your "intuitive" order, a NPE will be thrown.

Why do fields seem to be initialized before constructor?

If you move your dog instance in the end, you may find the output becomes -2

public class Dog {

static final int val1 = -5;// This is final, so will be initialized at compile time
static int val2 = 3;
public int val3;

public static Dog dog = new Dog();//move to here

public Dog() {
val3 = val1 + val2;
}

public static void main(String[] args) {
System.out.println(Dog.dog.val3);//output will be -2
}
}

The final fields(whose values are compile-time constant expressions) will beinitialized first, and then the rest will be executed at in textual order.

So , in your case when dog instance is initialized, static int val2(0) is not initialized yet, while static final int val1(-5) does since it is final.

http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.4.2 states that:

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, except that
final class variables and fields of interfaces whose values are
compile-time constants are initialized first



Updated a newer doc

Here is the jdk7 version from http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2

final field is at step6:

Then, initialize the final class variables and fields of interfaces
whose values are compile-time constant expressions

while static field is at step 9:

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.

Java - Method executed prior to Default Constructor

Instance variable initialization expressions such as int var = getVal(); are evaluated after the super class constructor is executed but prior to the execution of the current class constructor's body.

Therefore getVal() is called before the body of the ChkCons constructor is executed.

What is object field initialization and constructor order in Java

Yes, in Java (unlike C#, for example) field initializers are called after the superclass constructor. Which means that any overridden method calls from the constructor will be called before the field initializers are executed.

The ordering is:

  • Initialize superclass (recursively invoke these steps)
  • Execute field initializers
  • Execute constructor body (after any constructor chaining, which has already taken place in step 1)

Basically, it's a bad idea to call non-final methods in constructors. If you're going to do so, document it very clearly so that anyone overriding the method knows that the method will be called before the field initializers (or constructor body) are executed.

See JLS section 12.5 for more details.

Making sure fields are initialized out of constructor

You should look at the Builder Pattern. There are number of articles that you can find on the internet on how to use it. This is one example https://jlordiales.me/2012/12/13/the-builder-pattern-in-practice/. Using the Builder pattern you can validate if certain fields are set or not and throw exception if there are not.

How are fields initialized by the default constructor

Explanation

As written in the JLS, fields are always automatically initizialized to their default value, before any other assignment.

The default for int is 0. So this is actually part of the Java standard, per definition. Call it magic, it has nothing to do with whats written in the constructor or anything.

So there is nothing in the source code that explicitly does this. It is implemented in the JVM, which must adhere to the JLS in order to represent a valid implementation of Java (there are more than just one Java implementations).

See §4.12.5:

Initial Values of Variables

Each class variable, instance variable, or array component is initialized with a default value when it is created (§15.9, §15.10.2)


Note

You can even observe that this happens before any assignment. Take a look at the following example:

public static void main(String[] args) {
System.out.println("After: " + x);
}

private static final int x = assign();

private static int assign() {
// Access the value before first assignment
System.out.println("Before: " + x);

return x + 1;
}

which outputs

Before: 0
After: 1

So it x is already 0, before the first assignment x = .... It is immediatly defaulted to 0 at variable creation, as described in the JLS.

Why instance variables get initialized before constructor called?

This is because at compile time, the compiler moves every initialization you have done at the place of declaration to every constructor of your class. So the constructor of UCMService class is effectively compiled to:

public UCMService(String service){
super(); // First compiler adds a super() to chain to super class constructor
dataMap = new DataMap(); // Compiler moves the initialization here (right after `super()`)
System.out.println("2222");
this.service = service;
}

So, clearly DataMap() constructor is executed before the print statement of UCMService class. Similarly, if you have any more constructor in your UCMService class, the initialization will be moved to all of them.


Let's see the byte code of a simple class:

class Demo {
private String str = "rohit";

Demo() {
System.out.println("Hello");
}
}

compile this class, and execute the command - javap -c Demo. You will see the following byte code of constructor:

Demo();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String rohit
7: putfield #3 // Field str:Ljava/lang/String;
10: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
13: ldc #5 // String Hello
15: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
18: return

You can see the putfield instruction at line 7, initializes field str to "rohit", which is before the print statement (instruction at line 15)



Related Topics



Leave a reply



Submit