23
public class Dog {

 public static Dog dog = new Dog();
 static final int val1 = -5;
 static int val2 = 3;
 public int val3;

 public Dog() {
      val3 = val1 + val2;
 }

public static void main(String[] args) {
    System.out.println(Dog.dog.val3);
}
}

The output is -5

From this result, it seems that the initialization of val2 is before the completion of dog member and its instantiating.

Why is this order like this?

Chao
  • 865
  • 8
  • 21
  • 1
    It could be that final fields are declared first (maybe because they are stored differently in the java bytecode) and non-final fields are declared after that in the order you wrote them. If this is right, then `val1` would be -5 at the point the `Dog` instance is declared, but val2 is still set to the default of 0. – Sirac Dec 10 '14 at 07:01
  • 3
    It is because final variable are loaded first when class loading and then remaining static variables in order in which they are declared. see http://stackoverflow.com/questions/12448465/in-what-order-are-static-blocks-and-static-variables-in-a-class-executed for more clarification – Adi Dec 10 '14 at 07:02
  • 6
    *final* int makes the int a *compile-time* constant. – TheLostMind Dec 10 '14 at 07:02

5 Answers5

21

If you move your dog instance in the end, you may find the output becomes -2

public class Dog {

     static final int val1 = -5;// This is final, so will be initialized at compile time 
     static int val2 = 3;
     public int val3;

     public static Dog dog = new Dog();//move to here
 
     public Dog() {
          val3 = val1 + val2;
     }

    public static void main(String[] args) {
        System.out.println(Dog.dog.val3);//output will be -2
    }
}

The final fields(whose values are compile-time constant expressions) will beinitialized first, and then the rest will be executed at in textual order.

So , in your case when dog instance is initialized, static int val2(0) is not initialized yet, while static final int val1(-5) does since it is final.

http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.4.2 states that:

execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block, except that final class variables and fields of interfaces whose values are compile-time constants are initialized first


Updated a newer doc

Here is the jdk7 version from http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2

final field is at step6:

Then, initialize the final class variables and fields of interfaces whose values are compile-time constant expressions

while static field is at step 9:

Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

Community
  • 1
  • 1
JaskeyLam
  • 15,405
  • 21
  • 114
  • 149
10

Variable declaration sequence. The static final int val1 is initialized first because it is a constant. However static int val2 is still 0 at the time public static Dog dog = new Dog(); is instantiated.

gknicker
  • 5,509
  • 2
  • 25
  • 41
6

What is happening..

The first line that is executing is this public static Dog dog = new Dog();. Now, there are 2 things that must be kept in mind.

  1. final int makes it a compile time constant. So, -5 is already hard-coded into your code.

  2. The call to new Dog() is done and the constructor is called which sets the value to 0 + -5 = -5.

change val2 to final then you will see the difference (you will get -2 as answer.)

Note : static fields are initialized as and how they are encountered.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
TheLostMind
  • 35,966
  • 12
  • 68
  • 104
4

Initialization sequence in your test;

  1. static final int val1 = -5; //constant as static final
  2. public static Dog dog = new Dog(); //then 'dog' is initialize but its member val2 has not been initialized
  3. static int val2 = 3; //at last 'val2' is initialized

This code change will output -2;

public class Dog {

     //public static Dog dog = new Dog();
     static final int val1 = -5;
     static int val2 = 3;
     public int val3;
     public static Dog dog = new Dog();     //moved here

     public Dog() {
          val3 = val1 + val2;
     }


    public static void main(String[] args) {
        System.out.println(Dog.dog.val3);

    }
}
Wundwin Born
  • 3,467
  • 19
  • 37
4

All static variables are initialized in a separate static constructor, which is executed on class loading. In the same order as they apear in the code. Your example is compiled into something like this:

public class Dog {

 public static Dog dog;
 static final int val1 = -5;
 static int val2;
 public int val3;

 static {
  dog = new Dog();
  val2 = 3;
 }

 public Dog() {
      val3 = val1 + val2;
 }

 public static void main(String[] args) {
     System.out.println(Dog.dog.val3);
 }
}

That's why order of class/instance variables matters. Class constructor execution happens at the end of initialization. Constants are resolved before. For more information refer to Creation of New Class Instances.

Mikhail
  • 4,175
  • 15
  • 31
  • Your example explains my program well, but I wonder if there is an official explanation about your argument "All static variables are initialized in a separate static constructor.." – Chao Jan 06 '15 at 12:07