2
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.

6 Answers 6

5

If you look at the decompiled byte code of Foo.class, you will notice the following:

  • The class' constructor itself only assigns the value 10 (bipush and putfield). The class's constructor does not first assign 0 and then 10.
  • The VM will have a default value of 0 for the field whenever it is accessed - no matter from which code. So this default value will not show up anywhere - at least not in the bytecode of the class or other classes which access the field for example by reflection. Primitive default values are baked into the VM.
  • Explicitly setting the default will produce different bytecode, see second example.

.

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
Sign up to request clarification or add additional context in comments.

Comments

3

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.

5 Comments

Well, that's not exactly true. As the field is private, and no accessors are defined, who says this can not be optimized?
@Axel: It would take more work to figure out which memory locations in the allocation don't need to be zeroed than to just zero the whole thing, so the optimization would backfire. Also, consider the case where the constructor fetches a private field using reflection. It's a case of dubious real-world value, but it demonstrates one of the reasons why fields behave the way they do during object construction -- even cases of dubious real-world value need to be defined. If this were a field of a reference type, leaving garbage in there as an optimization would be a serious security risk...
Well let's not confuse things here. The compiler does the search at compile time, in order to save an initialization at run time
This is the answer that I think gave the best explanation. Thank you.
@Axel: But the JVM code that allocates the object's memory on the heap will zero the memory. Again, the compiler is not responsible in any way for object allocation. This is a runtime matter. The compiler does not emit any code to set the default values of fields (except where you explicitly initialize them), even if you were to include the println call. At the moment the constructor is entered, the field has its default value because of the runtime's behavior.
3

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;
    }
}

4 Comments

-1, but only IF you access the variable prior using it in the constructor!
But, we ARE talking about about accessing inside the constructor
You can call a method which looks at 'var' before its assigned, even for final variables.
@Peter That's true, however I believe this is not what is being asked here
1

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.

2 Comments

No offense, but who cares what C# would do?
@Erick: Plenty of people, given that they're similar languages and many people use both. Given that this can trip people up, I think it's worth a single sentence at the end of a detailed post.
0

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.