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:
- Parent's fields are initialized
- Child's fields are initialized
- Parent's constructor is called
- 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
How to Secure an API Rest For Mobile App (If Sniffing Requests Gives You the "Key")
Semicolon At End of 'If' Statement
Converting 'Arraylist≪String≫ to 'String[]' in Java
Split String to Equal Length Substrings in Java
Java Error: Comparison Method Violates Its General Contract
Getting Hold of the Outer Class Object from the Inner Class Object
Difference Between Volatile and Synchronized in Java
Java Hashmap: How to Get Key from Value
Difference Between Inheritance and Composition
What Is an Initialization Block
Check Whether a String Is Not Null and Not Empty
How to Get the Separate Digits of an Int Number
Convert a Json String to Object in Java Me
Calendar Date to Yyyy-Mm-Dd Format in Java