Reputation: 7334
public class Foo {
private int var;
public Foo() {
var = 10;
}
}
In this code snippet, would var
first be assigned a default value and then reassigned to 10, or would it be assigned to 10 directly without being assigned a default value?
Somewhat a trivial question, but I'm curious.
Upvotes: 2
Views: 151
Reputation: 2098
The language specification says:
Otherwise, all the instance variables in the new object, including those declared in superclasses, are initialized to their default values (§4.12.5).
http://java.sun.com/docs/books/jls/third_edition/html/execution.html#44410
Then the constructor is called.
Upvotes: 0
Reputation: 14232
If you look at the decompiled byte code of Foo.class
, you will notice the following:
.
public class Foo {
private int var;
public Foo();
0 aload_0 [this]
1 invokespecial java.lang.Object() [10]
4 aload_0 [this]
5 bipush 10
7 putfield Foo.var : int [12]
10 return
If you write the following:
public class Foo {
private int var = 0;
public Foo() {
var = 20;
}
}
the bytecode will be:
0 aload_0 [this]
1 invokespecial java.lang.Object() [10]
4 aload_0 [this]
5 iconst_0
6 putfield Foo.var : int [12]
9 aload_0 [this]
10 bipush 20
12 putfield Foo.var : int [12]
15 return
The next example shows that accessing the variable will still not lead to an assignment of any value:
public class Foo {
private int var;
public Foo() {
System.out.println(var);
var=10;
}
}
This code will print 0
because getField Foo.var
at opcode 8 will push "0" onto the operand stack:
public Foo();
0 aload_0 [this]
1 invokespecial java.lang.Object() [10]
4 getstatic java.lang.System.out : java.io.PrintStream [12]
7 aload_0 [this]
8 getfield Foo.var : int [18]
11 invokevirtual java.io.PrintStream.println(int) : void [20]
14 aload_0 [this]
15 bipush 10
17 putfield Foo.var : int [18]
20 return
Upvotes: 5
Reputation: 35169
According to the spec: (Section 4.2.15)
First 0.
Then 10.
If you would read it first in the constructor, you would get 0.
public class Foo {
private int var;
public Foo() {
System.out.println(var); //0
var = 10;
}
}
Upvotes: 3
Reputation: 1499730
It would be given the default value first. In particular, if Foo was derived from Bar, and the constructor of Bar could get at the value of var somehow (e.g. through a virtual method declared in Bar and overridden in Foo), that default value would be visible, even if the variable is final. For example:
class Parent {
public Parent() {
showVariables();
}
public void showVariables() {
}
}
class Child extends Parent {
private final int x;
public Child() {
x = 10;
}
@Override
public void showVariables() {
System.out.println("x = " + x); // Prints x = 0
}
}
public class Test {
public static void main(String[] args) {
new Child();
}
}
Note that this still happens even when the field is initialized at the point of declaration:
public class Foo {
private int var = 10;
public Foo() {
// Implicit call to super constructor - this occurs *before*
// var is assigned the value 10
}
}
In this respect Java differs from C#. In C#, var
would be assigned the value 10 before the call to the base constructor.
Upvotes: 1
Reputation: 168978
Uninitialized fields will always be assigned the default value prior to calling the constructor, because the runtime will zero the memory allocation for the object prior to calling the constructor. It must do this because it does not know what the constructor might do ahead of time, and because derived classes may live in other jars/classpaths and fetch the value (if it's protected) or call into a method that uses the field before it is initialized by the constructor.
This is performed independently of the compiler, and therefore this is not something the compiler can optimize away, and the compiler doesn't even have control over this.
Upvotes: 3
Reputation: 533442
Assigning the default value implies it had a value before you assigned the default value. An object has the default value when it is created, it is not assigned it.
If you look at the byte code, the only code is to assign the new value.
Upvotes: 0