I have this simple piece of code.
abstract class X {
X() {
read();
}
private void read() {
Object obj = new Object();
readValue(obj);
}
protected abstract void readValue(Object obj);
}
class Y extends X {
Object obj = null;
Y() {
super();
}
#Override
protected void readValue(Object obj) {
this.obj = obj;
}
void printer() {
System.out.println("Object = " + obj);
}
}
class Runner {
public static void main(String[] args) {
Y y = new Y();
y.printer();
}
}
When I run the above code, the object gets printed as null. (I get "Object = null")
Surprisingly, in class Y when I remove null declaration
Object obj;
The actual value of the object is printed.
Something like ("Object = java.lang.Object#3cd1a2f1")
Why is such a behavior observed? What is 'this' pointing to? Any object is initialized by null if we just declare it, then why such an aberrant behavior?
The reason the obj field is null is due to the sequence of steps that occur in the constructor call of Y:
The constructor of Y calls the super constructor which eventually calls readValue of the concrete class Y, therefore assigning a non-null value to the obj field.
After the super constructor finishes, the instance field obj is initialized to null due to the variable initializer:
Object obj = null;
When you remove the null initializer, it becomes a simple field declaration with no instance initialization to be performed in step 2.
The apt solution is not to remove the null initializer, but to re-design the whole class hierarchy. For example, since the purpose of readValue seems to just be a setter for a variable, then you don't need to make it override an abstract method in the parent class. Just set it as a separate method and call it after the constructor of Y completes.
This illustrates the dangers of calling an inherited method in a subclass from a superclass constructor. The main danger is that initializers for variables in a subclass run after the superclass constructor completes.
Here is what happens.
An object of y is created.
The superclass constructor X() is called, which calls read().
The read method creates a new Object and passes it to readValue, which is implemented in Y.
The readValue method in Y sets obj to the new object.
The superclass constructor X() completes, and initializers run now in Y, setting obj to null.
The printer method prints "Object = null".
If you remove the declaration of obj in Y, then there is no initializer to run, and the obj variable retains its value.
The JLS, Section 12.5, states:
[A]ll the instance variables in the new object, including those declared in superclasses, are initialized to their default values (§4.12.5).
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.
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.
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.
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.
(emphasis mine)
and
Unlike C++, the Java programming language does not specify altered rules for method dispatch during the creation of a new class instance. If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely initialized.
The object is null because The superclass constructor runs before the subclass constructor,hence it would only be natural that the statement Object obj = null; is executed after calling super class constructor.
The assignment of Object obj = null; is inlined into the constructor during compile time. This are only accessible in existing instance,
and instance does not exist yet when you are in constructor (it is still under construction).
You can achieve object value(Object = java.lang.Object#3cd1a2f1) by declaringobject object as static.
static Object obj = null;
Generally though, it's bad practice to call overriden methods from a constructor in real time.
Related
I tried to go through almost every article here about variable initializations, but I still do not understand couple things about it. It is not clear for me if we HAVE TO call the constructor to initialize the instance variables to default values or it can happen without invoking the constructor? For example, convention is that every class written by us in Java is invoking a super class constructor in its constructor to "initialize variables" of super class. What does it exactly mean? Do we have to invoke a super class constructor to initialize instance variables of super class to default values? Or even without invokin super class constructor instance variables have an default values, and we are doing this to pass them the values described in constructor or given during the declaration? The second thing is, that we can initialize variables in couple ways, by not giving them a values (they will be set to default values), giving values in declaration, for example:
private int number = 10;
or specifing values in a constructor. It is clear for me, that we have to invoke the constructor to initialize variables to values specified in constructor but what about other 2 examples? Do we also have to invoke constructor to initialize instance variable to these values? Can someone also give me an order for creating this in simple words? I know that there are a lot of articles here about order of object instantiation and initialization and i have read them all, but I still do not understand a lot of things there.
And tell me if I am wrong, but what I understanded, the answer to question is that we have to invoke a super class constructor to initialize super class fields to their default values because in the other way there will be no point to making a call the super class constructors necessary if the instance variables of super class would be already initialized with default values without calling the constructor - because we wouldnt have to worry that our variables are uninitialized if they are - with default values.
#EDIT: To be clear, my main question was:
When instance variables are getting a default value? In the constructor or before the constructor? Do constructor have to be called to initialize the instance variables, or the default values are assigned even before the constructor call?
In an Object Oriented Programming Languages "Object" plays the Key role. So, initiating the object is must. I couldn't exactly get what you are asking.. I'm telling according to my knowledge.
You have to instantiate a class to use its fields & methods. For that you are assigning like this
Class_Name object = new Class_Name();
no problem whether you are creating a default constructor in the invoking class it will creates a default one.
But, once you created a constructor with parameters you have to create a default constructor to initiate an Object like above.
You may assign values to variables in the class as you described & through parameterized constructors. Its best to write private modifier for initiating a variable (here comes Encapsulation Concept).
You can change the value of the instantiated variable through passing a parameter in constructor.
If you haven't put any values for your variables. Compiler will put a default value for that.
Have a look at this article
https://www.javaworld.com/article/2076614/core-java/object-initialization-in-java.html
According to JLS 4.12.5:
Every variable in a program must have a value before its value is
used:
Each class variable, instance variable, or array component is
initialized with a default value when it is created (§15.9, §15.10.2):
For type byte, the default value is zero, that is, the value of
(byte)0.
For type short, the default value is zero, that is, the value of
(short)0.
For type int, the default value is zero, that is, 0.
For type long, the default value is zero, that is, 0L.
For type float, the default value is positive zero, that is, 0.0f.
For type double, the default value is positive zero, that is, 0.0d.
For type char, the default value is the null character, that is,
'\u0000'.
For type boolean, the default value is false.
For all reference types (§4.3), the default value is null.
Each method parameter (§8.4.1) is initialized to the corresponding
argument value provided by the invoker of the method (§15.12).
Each constructor parameter (§8.8.1) is initialized to the
corresponding argument value provided by a class instance creation
expression (§15.9) or explicit constructor invocation (§8.8.7).
An exception parameter (§14.20) is initialized to the thrown object
representing the exception (§11.3, §14.18).
A local variable (§14.4, §14.14) must be explicitly given a value
before it is used, by either initialization (§14.4) or assignment
(§15.26), in a way that can be verified using the rules for definite
assignment (§16 (Definite Assignment)).
So if your field is not being initialized anywhere before it is being used, the initial (or default) value would be null for object/reference types, false for primitive boolean type, or 0 for any other primitive types (0 for char is null character).
If the field is initialized, then we need to look at the order.
private class A {
protected int a = 2;
public A() {
System.out.println("Printing from constructor of A");
printValues();
System.out.println();
}
public void printValues() {
System.out.println("a = " + a);
}
}
private class B extends A {
private int b = 3;
private int c = initC();
public B() {
super();
System.out.println("Printing from constructor of B");
printValues();
System.out.println();
}
#Override
public void printValues() {
super.printValues(); // Call parent implementation
System.out.println("b = " + b);
System.out.println("c = " + c);
}
private int initC() {
System.out.println("Printing from initC()");
printValues();
System.out.println();
return 4;
}
public static void main(String[] args) {
new B();
}
}
This generates:
Printing from constructor of A
a = 2
b = 0
c = 0
Printing from initC()
a = 2
b = 3
c = 0
Printing from constructor of B
a = 2
b = 3
c = 4
In the constructor of A (which is the parent class), a (which belongs to A) is already initialized with 2. The other 2 fields remains un-initialized, returning values specified by JLS 4.12.5.
Then the constructor of A finishes and returns back to the constructor of B (the child class). You would have expected it to go to the B constructor part, but something else happened before that - initC() is being called. At this point, we can see that b has also been initialized, but c hasn't been initialized because initC() is supposed to return the value to initialize c.
Lastly, we see all the 3 fields being initialized.
So this is the order:
Most super class' fields are initialized first.
When returning from super class' constructor, the child class initializes its own fields.
Constructor continues to execute, which allows you to use the initialized values.
So initializing inline at field declaration allows you to be sure that the field has the value when you use it even at constructor, while initializing at constructor could only ensure the value is initialized after it exits the constructor (child class can be sure that it is initialized too).
When instance variables are getting a default value? In the constructor or before the constructor?
Before the constructor. If they got their default value after the constructor, then there would be no point setting them to a different value inside the constructor.
Do constructor have to be called to initialize the instance variables, or the default values are assigned even before the constructor call?
It doesn't matter, the constructor is always called when you make a new instance. If you write a subclass that doesn't explicitly call its superclass's constructor, then the superclass's no-args constructor will be automatically called.
For instance, this:
class B extends A {
public B() {}
}
is equivalent to this:
class B extends A {
public B() {
super();
}
}
If you don't call the superclass constructor explicitly, then your superclass's no-args constructor will be called. If no such constructor exists, then your code will not compile.
A constructor is always called.
I have just started learning Java.I understand
Unlike instance method, instance variable can not be overridden, and are not dynamically picked by JVM at run time when accessed polymorphically.
flow of execution : static block, super constructor, initialization block and then constructor.
But I am stuck at one code, where I have polymorphically invoked a instance variable but its showing overridden value (which it should not show). The instance variable is overridden inside sub class' init block.
package package1;
public class Other {
public static void main(String [] args){
Parent referToChild = new Child();
Parent referToChildTwo = new ChildTwo();
System.out.println("age as referred by referToChild reference variable is:" + referToChild.age);// prints 35 (doubt 1)
System.out.println("age as referred by referToChildTwo reference variable is:" + referToChildTwo.age);// prints 50 (doubt 2)
System.out.println("money as referred by Other reference variable is:" + referToChild.money);
//System.out.println("Other reference variable is:" + othObj.age);
}
}
class Child extends Parent{
// init block
{
age = 35;
}
}
class ChildTwo extends Parent{
public int age;
{
age = 40;
}
}
class Parent{
public int age = 50;
public int money = 100;
}
The answer I get is:
35
50
100
so my doubts are:
doubt 1 :Why is it showing "35", it should display super class' variable's value which is 50.
doubt 2 : When it is displaying sub class' variable's value for last case, then why not for this case.
Why is it showing "35", it should display super class' variable's value which is 50.
The initializer block of subclass Child executes after the variable age is initialized in the Parent class. Therefore, age is first initialized to 50, then to 35.
This is explained in great detail in the Java Language Specification Section 12.5 on Creation of New Class Instances, with the relevant part in bold:
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.
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.
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.
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 for the second question, referToChildTwo is declared of type Parent, while its actual type is ChildTwo. A ChildTwo instance has two age fields, the one defined in ChildTwo and the other one inherited from Parent.
When you write the expression referToChildTwo.age, the field inherited in Parent will be evaluated. To evaluate the one defined in the subclass, you would need to cast the variable, i.e. ((ChildTwo)referToChildTwo).age.
It cannot be overridden, but it is inherited by child classes as long as it wasn't private in the parent. And they can access it, including both reading and writing it.
Overriding is creating a new member which is part of the current class, which has the same definition of the member of the parent class, and for that member to be accessed when you use the object polymorphically.
For example:
class Parent {
public int age = 50;
}
class Child {
public int age = 80;
}
Here we defined a new member, age, which is separate from the parent's age. If you access it from inside Child using this.age, you'll get 80. If you access the parent's age using super.age, you'll get 50.
But this is not overriding, because if you use the object polymorphically, it will access the parent's age:
Child childObj = new Child();
Parent parentObj = childObj;
System.out.println( childObj.age ); // Will print 80
System.out.println( parentObj.age ); // Will print 50
This is despite the fact that they are both the same object. That's because the child hides the field rather than override it.
Simply assigning a value in a field inherited from the parent is not overriding. It's part of what inheritance is all about.
I thought the result could be '43' because the type of q was 'poly 1'. However, the result was '44'. I couldn't understand that. please give me the answer.
class poly1 {
int a;
public poly1(){
a = 3;
}
public void print_a(){
System.out.print(a);
}
}
public class poly2 extends poly1{
public poly2(){
a = 4;
}
public void print_a(){
System.out.print(a);
}
public static void main(String[] args){
poly2 p = new poly2();
p.print_a();
poly1 q = new poly2();
q.print_a();
}
}
When you invoke a class' constructor, the class' super type constructor is invoke first (until there is no super types).
When you invoke
new poly2();
The poly1 constructor is invoked first (because poly1 is a super type of poly2), setting a to 3 and then the poly2 constructor is invoked, setting a to 4 which is what you see.
the type of q was 'poly 1'
What seems to confuse you is that in the following code
poly1 q = new poly2();
the variable q is declared as type poly1. That makes no difference in this case. What actually matters is the run time type of the object. That's determined by the new statement. In this case, the object is of dynamic type poly2.
When you run this program,at
poly2 p = new poly2();
a's value is 4 as it initialised by the constructor of poly2, again at
poly1 q = new poly2();
a's value is initalised by the constructor of poly2 to 4,so it will print 4 again giving a output of "44".
Everytime u instatiate "p" and "q" ,the value of "a" is first initialised by the constructor of poly1 and again the calue of "a" gets initialised by constructor of class poly2 as poly2 extends poly1 class.
Try debugging the code and you will get to know the exact flow of the program.
According to the language specs, instance variables aren't even initialized until a super() call has been made.
These are the steps performed during the constructor step of class instance creation/
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
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.
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.
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.
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.
Sorry about my earlier answer.. Apparently, I hadn't seen the question correctly...
public static void main(String[] args){
poly2 p = new poly2();
p.print_a();
poly1 q = new poly2();
q.print_a();
}
Now, when you do :
poly2 p = new poly2();
The following happens..
poly2 constructor is called.
poly2 constructor forwards the creation call to poly1 constructor.
The value of a is 3 (initialized in poly1 constructor)
The control comes back to poly2 constructor
a is set to 4 in poly2 constructor.
The same thing happens in the second case as well.
they are all realize of Poly2, so they use the structure function of Poly2, so console display"44"
When you run this program,at the below line
poly2 p = new poly2();
a's value is 4 as it initialised by the constructor of poly2, again at the below line
poly1 q = new poly2();
the refrence you are creating is of poly1 but at runtime the object is created of poly2 so at this line a's value becomes 4 that's why you are getting the result 44.
Methods are invoked by looking at object. In your case the object is of class Poly2 so in both the case it will invoke Poly2 class's print_a method.
Addition
Execution of constructor matters here. sequence of execution of constructor is first base class constructor and then derived class constructor.
I have a few cases I wonder about. First, if you have no constructor:
class NoCons { int x; }
When I do new NoCons(), the default constructor gets called. What does it do exactly? Does it set x to 0, or does that happen elsewhere?
What if I have this situation:
class NoCons2 extends NoCons { int y; }
What happens when I call new NoCons2()? Does NoCons's default constructor get called, and then NoCons2's constructor? Do they each set the respective x and y fields to 0?
What about this version:
class Cons2 extends NoCons { int y; public Cons2() {} }
Now I have a constructor, but it doesn't call the super class's constructor. How does x ever get initialized? What if I had this situation:
class Cons { int x; public Cons() {} }
class NoCons2 extends Cons { int y; }
Will the Cons constructor be called?
I could just try all these examples, but I can't tell when a default constructor is run. What's a general way to think about this so that I'll know what happens in future situations?
When a Java class has no constructor explicitly defined a public no-args default constructor is added so:
class Cons { int x; }
is equivalent to:
class Cons { int x; public Cons() {} }
A subclass's constructor that doesn't explicitly define which of its parent's constructor it calls will automatically call the default constructor in the parent class before it does anything else. So assuming:
class A { public A() { System.out.println("A"); } }
then this:
class B extends A { public B() { System.out.println("B"); } }
is exactly equivalent to:
class B extends A { public B() { super(); System.out.println("B"); } }
and the output in both cases will be:
A
B
So when you do:
new NoCons2();
The order is:
NoCons's default constructor called, although this is technically the first part of (2); and then
NoCons2's default constructor called.
You want to refer to the Java Language Specification section 12.5 Creation of New Class Instances to get the official rules of object creation. The relevant section is:
Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
If this constructor begins with an explicit constructor invocation 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.
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.
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. (In some early implementations, the compiler incorrectly omitted the code to initialize a field if the field initializer expression was a constant expression whose value was equal to the default initialization value for its type.)
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.
So in your examples, when no constructor is supplied in your class definition, the default one is inserted for you. When you write
new NoCons2();
First the super constructor is called (a call to super() is inserted for you because you don't make the call explicitly).
Instance variables for the class being constructed are initialized.
The rest of the constructor body is executed (nothing in your case).
In your first example, x will be set during the construction of NoCons and y will be set during the construction of NoCons2.
So the exact sequence of events in that example will be something like:
NoCons2 constructor called.
Call to super(), goto 3
NoCons constructor called.
Call to super(), which is an implicit call to Object().
Whatever happens in Object constructor.
x is set to 0.
finish body of NoCons constructor, return control back to NoCons2 constructor.
y is set to 0.
finish body of NoCons2 constructor
NoCons2 object construction complete.
cletus answered the biggest of the questions. The answer to the other is that member variables in Java are initialized to 0, null or false (depending on the type).
Here is essentially what happens when "new" is called:
the memory is allocated (enough to hold all of the data members of the class, and all of the parent classes, and some housekeeping information)
the allocated memory is set to zero (which means 0, 0.0, false, null depending in the type)
the constructor is called for the class that is after "new" is called.
more things happen (coming after the next part)
If you do not provide a constructor the compiler does the following:
creates a no-argument constructor
the created constructor has the same access as the class (so public or package)
super() is called.
So when the constructor of the class after the "new" is called the very first thing it does is call "super()" which calls the parent constructor. This happens all the way up to java.lang.Object.
Before the body of the constructor is run the VM does the following:
the instance variables that are assigned values are given them
then the instance initializer block, if present is run.
The following code shows all of this:
public class Main
{
private Main()
{
}
public static void main(final String[] args)
{
final Foo fooA;
final Foo fooB;
fooA = new Foo(7);
System.out.println("---------------------");
fooB = new Foo(42);
}
}
class Bar
{
protected int valueA = getValue("valueA", 1);
protected int valueB;
static
{
System.out.println("static block for Bar happens only one time");
}
{
System.out.println("instance block for Bar happens one time for each new Bar");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
}
Bar()
{
super(); // compiler adds this - you would not type it in
System.out.println("running Bar()");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
valueB = getValue("valueB", 2);
}
protected static int getValue(final String name, final int val)
{
System.out.println("setting " + name + " to " + val);
return (val);
}
}
class Foo
extends Bar
{
protected int valueC = getValue("valueC", 1);
protected int valueD;
static
{
System.out.println("static block for Foo happens only one time");
}
{
System.out.println("instance block for Foo happens one time for each new Foo");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
}
Foo(final int val)
{
super(); // compiler adds this - you would not type it in
System.out.println("running Foo(int)");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
valueD = getValue("valueD", val);
}
}
class test
{
test() {
System.out.println("Constructor");
}
{ System.out.println("Hai"); }
}
public class sample
{
public static void main(String [] a) {
test t = new test();
}
}
In the above code, why is "Hai" printed before the test() constructor is called?
The test() constructor in the test class is above the "Hai" statement and should be called first, right?
Let express with a more clear example:
public class Test {
static {
System.out.println("static initializer");
}
{
System.out.println("instance initializer");
}
public Test() {
System.out.println("constructor");
}
}
and test it as follows:
public class Main {
public static void main(String[] args) {
Test test1 = new Test();
Test test2 = new Test();
}
}
output:
static initializer
instance initializer
constructor
instance initializer
constructor
The static initializers are executed only once during runtime, specifically during loading of the class. The instance initializers are executed during every instantiation before the constructor.
You can have more than one of them and they will be executed in the order as they appear in the coding.
The major benefit of instance initializers is that they are executed regardless of which constructor you use. They applies on each of them so that you don't need to duplicate common initialization over all of them.
The major benefit of static initializers is that they are executed only once during class loading. A well known real world example is the JDBC driver. When you do
Class.forName("com.example.jdbc.Driver");
which only executes the static initializers, then any (decent) JDBC driver will register itself in the DriverManager as follows
static {
DriverManager.registerDriver(new com.example.jdbc.Driver());
}
this way the DriverManager can find the right JDBC driver during getConnection().
Yes. It's an instance initializer. It's run as soon as the class is instantiated.
In the above code why is that the statement given within the braces ((i.e) "Hai") is Printed before the constructor is executed.
Because this is the expected behavior as described in the section 12.5 Creation of New Class Instances of the Java Language Specification :)
Just before a reference to the newly
created object is returned as the
result, the indicated constructor is
processed to initialize the new object
using the following procedure:
Assign the arguments for the constructor to newly created parameter
variables for this constructor
invocation.
If this constructor begins with an explicit constructor invocation 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.
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.
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. (In some early
implementations, the compiler
incorrectly omitted the code to
initialize a field if the field
initializer expression was a constant
expression whose value was equal to
the default initialization value for
its type.)
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.
See section 8.6 Instance Initializers for more details on... instance initializers.
Braces immediately within a class introduces an instance initialiser (introduced in Java 1.1). They are treated much the same as code to assign fields written as part of the declaration. So the following are equivalent:
private final Thing x = new Thing();
and
private final Thing x;
{
x = new Thing();
}
The code is executed by constructors immediately after calling a super constructor. So, assuming no other initialisation, the code can be written equivalently as part of the constructor:
private final Thing x;
public MyCLass() {
super(); // Often implicit.
x = new Thing();
}
Braces in the same position preceded by the static keyword and static initialisers, executed once when a class is initialised, not on a per-instance basis.