"The verifier rejects code that uses the new object before it has been initialized."
In bytecode verification, since the verifier works at link-time, the types of local variables of methods are inferred. The types of method arguments are known as they are in the method signature in the class file. The types of other local variables are not known and are inferred, so I assume the "uses" in the above statement relates to this.
EDIT:
The section 4.9.4 of the JVMS reads:
The instance initialization method (§3.9) for class myClass sees the new uninitialized object as its this argument in local variable 0. Before that method invokes another instance initialization method of myClass or its direct superclass on this, the only operation the method can perform on this is assigning fields declared within myClass.
This assignment of fields in the above statement is the "initial" initialization of the instance variables to default initial values (like int is 0, float is 0.0f etc.) when the memory for the object is allocated. There is one more "proper" initialization of instance variables when the virtual machine invokes the instance initialization method(constructor) on the object.
The link provided by John Horstmann helped clarify things.
So these statements dont hold true. "This DOESNOT mean that in an <init>
method, getfield
and putfield
are allowed before another <init>
is called."
The getfield
and putfield
instructions are used to access (and change) the instance variables(fields) of a class (or instance of a class). And this can happen only when the instance variables(fields) are initialized."
From the JVMS :
Each instance initialization method
(§3.9), except for the instance
initialization method derived from the
constructor of class Object, must
call either another instance
initialization method of this or an
instance initialization method of its
direct superclass super before its
instance members are accessed.
However, instance fields of this that
are declared in the current class may
be assigned before calling any
instance initialization method.
When the Java Virtual Machine creates a new instance of a class, either implicitly or explicitly, it first allocates memory on the heap to hold the object's instance variables. Memory is allocated for all variables declared in the object's class and in all its superclasses, including instance variables that are hidden. As soon as the virtual machine has set aside the heap memory for a new object, it immediately initializes the instance variables to default initial values. Once the virtual machine has allocated memory for the new object and initialized the instance variables to default values, it is ready to give the instance variables their proper initial values. The Java Virtual Machine uses two techniques to do this, depending upon whether the object is being created because of a clone() invocation. If the object is being created because of a clone(), the virtual machine copies the values of the instance variables of the object being cloned into the new object. Otherwise, the virtual machine invokes an instance initialization method on the object. The instance initialization method initializes the object's instance variables to their proper initial values. And only after this can you use getfield
and putfield
.
The java compiler generates atleast one instance initialization method(constructor) for every class it compiles. If the class declares no constructors explicitly, the compiler generated a default no-arg constructor that just invokes the superclass no-arg constructor. And rightly so doing any operation on an instance field before a call to super()
or this()
results in a compilation error.
An <init>
method can contain three kinds of code: an invocation of another <init>
method, code that implements any instance variable initializers, and code for the body of the constructor. If a constructor begins with an explicit invocation of another constructor in the same class (a this()
invocation) its corresponding <init>
method will be composed of two parts:
- an invocation of the same-class
<init>
method
- the bytecodes that implement the body
of the corresponding constructor
If a constructor does not begin with a this()
invocation and the class is not Object, the <init>
method will have three components:
- an invocation of a superclass
<init>
method
- the bytecodes for any instance
variable initializers
- the bytecodes that implement the body
of the corresponding constructor
If a constructor does not begin with a this()
invocation and the class is Object(and Object has no superclass), then its <init>
method cant begin with a superclass <init>
method invocation.
If a constructor begins with an explicit invocation of a superclass constructor ( a super()
invocation), its <init>
method will invoke the corresponding superclass <init>
method.
I think this answers your first and second question.
Updated:
For example,
class Demo
{
int somint;
Demo() //first constructor
{
this(5);
//some other stuff..
}
Demo(int i) //second constructor
{
this.somint = i;
//some other stuff......
}
Demo(int i, int j) //third constructor
{
super();
//other stuffff......
}
}
Heres the bytecode for the above three constructors from the compiler(javac):
Demo();
Code:
Stack=2, Locals=1, Args_size=1
0: aload_0
1: iconst_5
2: invokespecial #1; //Method "<init>":(I)V
5: return
Demo(int);
Code:
Stack=2, Locals=2, Args_size=2
0: aload_0
1: invokespecial #2; //Method java/lang/Object."<init>":()V
4: aload_0
5: iload_1
6: putfield #3; //Field somint:I
9: return
Demo(int, int);
Code:
Stack=1, Locals=3, Args_size=3
0: aload_0
1: invokespecial #2; //Method java/lang/Object."<init>":()V
4: return
In the first constructor, the <init>
method begins with calling the same-class <init>
method and then executed the body of the corresponding constructor. Because the constructor begins with a this()
, its corresponding <init>
method doesnot contain bytecode for initializing the instance variables.
In the second constructor, the <init>
method for the constructor has
- super class
<init>
method, ie,
invocation of the superclass
constructor(no arg method), the
compiler generated this by default
because no explicit super()
was found
as the first statement.
- the bytecode for initializing the
instance variable
someint
.
- bytecode for rest of the stuff in the
constructor body.