|
Re: Need Help on order of constructors calls
|
Posted: Aug 13, 2004 5:13 PM
|
|
Here is what happens when you instantiate a class as:
new B();
1. JVM determines the memory that is needed to hold the values(or references ) of instance variables of this class. The instance varibles from ancestor classes are also included in the list. 2. JVM allocates the memory determined in STEP 1 + some extra memory to store info about the object. This extra memory depends on JVM implementation. For example, Sun JMV uses 3 machine words always, whereas IBM JVM uses 2 machine words for all objects except arrays. For an array object, IBM JVM also uses 3 machine words.
3. All instance varibles are assigned their default values. That is, primitives numerics are assigned zero, boolean false and reference types null.
4. At this stage object exists in memory with all its instance variables having their respective data type default values. The object referene is represented by keyword "this".
5. Then this "this" is passed to the constructor being called with new operator. In your case, the call new B() is replaced by new B(this);
Here, this is nothing but the reference of object created in STEP 1,2.
6. The constructor of B is called. JVM determines that B is inherited from A. So, before it starts executing construtor of B, it calls the constructor of A passing the argument "this". So, now A(this) is invoked, where "this" is nothing but the reference to an object of B created in STEP 1, 2.
7. When A(this) is called, JVM determines that class A is inherited from java.lang.Object class. So, JVM repeats the STEP 6 and the constructor of Object class, Object(this) is called. Again, "this" in Object(this) is the reference to object of clss B created in STEP 1,2.
8. When Object(this) , that is, the constructor of Object class is invoked, then JVM determines that there is no ancestor of Object class. At this time, JVM assigns the initial values to the instance variables of Object class. Note that, this assignment of initial values uses the user suppllied initial values. That is, if an instance variable is: int a = 101; then 101 is assigned to a in this step. However, zero was assigned to a in STEP 3.
(At this time, JVM executes the non-static initilaizer for Object class, if any). We will ignore this step in our discussion.
Now, JVM completes the constructor call to Object (this).
9. The control returns to A (this) call. Before, JVM starts executing any of the code in A() construtor, it initializes all instance variables defined in A with user supplied values. Now code inside A() construtor is excuted. Note that A() gets a hidden argument "this". In fact, A() is A (this) and we know that "this" is a reference of an object of class B created in STEP 1,2. So, when doSomething() in A() is excuted it is excuted as this.doSomething() and "this" is an object of B, where B has overriden doSomething() method. So, doSomething() of B class is executed. Note that this is possible only because in STEP 1, 2, an object of class B was created. Constructor is just a chance given to programmer to initialize the instance variables of that object.
10. Now, control comes to B(this). JVM initializes of instance variables of B and then executes this.doSomething(). Since B's instance variables were initialized at this time when doSomething() was called you get 111 printed, whereas when doSomething() was called in STEP 9, you get 0 printed.
The main point you need to note is that an object is created with default values for instance variables well before the construtor is called. It is the "new" operator that creates the object and then constructor is called. It is also advisable not to call methods from inside constructor. The reason is that your object may not be initialized the way you intendd to. For example, in your case, you always wanted to see 111 printed whenever doSomething() on B's object is called. Howveer, because of the order of initailization of objects, you saw different results.
Thanks Kishori
|
|