I have this following piece of code:
public abstract class UCMService{
private String service;
protected DataMap dataMap = new DataMap();
protected class DataMap extends HashMap<String,String> {
private static final long serialVersionUID = 4014308857539190977L;
public DataMap(){
System.out.println("11111");
put("IdcService",service);
}
}
public UCMService(String service){
System.out.println("2222");
this.service = service;
}
}
Now in console the System.out.println
of DataMap
constructor is executing before the constructor of UCMService
.
I was wondering why it is happening.
In Java, the order for initialization statements is as follows: static variables and static initializers in order. instance variables and instance initializers in order. constructors.
It makes sense to initialize the variable at declaration to avoid redundancy. It also makes sense to consider final variables in such a situation. If you know what value a final variable will have at declaration, it makes sense to initialize it outside the constructors.
Instance variables of numerical type (int, double, etc.) are automatically initialized to zero if you provide no other values; boolean variables are initialized to false; and char variables, to the Unicode character with code number zero. An instance variable can also be a variable of object type.
Java designers believe every variable should be properly initialized. To initialize a variable is to give it a correct initial value. It's so important to do this that Java either initializes a variable for you, or it indicates an error has occurred, telling you to initialize a variable.
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
)
Short answer:
Because the spec says so.
Long answer:
It would be very strange for the constructor to be unable to use inline-initialized fields.
You want to be able to write
SomeService myService = new SomeService();
public MyConstructor() {
someService.doSomething();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With