See the following program, and you guess the running result:

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

Now, I tell you the result is -5. But why?

To clarify this confusing initialization order, you must know a little about the memory layout and what the JVM do (imagine yourself as the compiler and VM).

Because static fields belong to the Class which located in the method area of JVM. The class initialization occurs in the class loading process by the class loader. The process is more or less like the one of plain object initialization other than the member fields of classes are static and class initialization doesn’t invoke any user-defined constructor.

One thing I must mention is that -5 is just CONSTANT, so assigning it to val1 means it is hard-corded into class file at compile-time. Therefore, final class variables and fields of interfaces whose values are compile-time constants are initialized first. 具有编译器常量的final类变量首先初始化!! http://docs.oracle.com/javase/sp…

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, except that final class variables and fields of interfaces whose values are compile-time constants are initialized first (§8.3.2.1, §9.3.1, §13.4.9).

To verify your thought, please see the decompiled bytecodes:


Classfile /playground/bin/playground/Dog.class
  Last modified Aug 25, 2016; size 725 bytes
  MD5 checksum 73b977e92851a8923319ee5a1032171a
  Compiled from "Dog.java"
public class playground.Dog
  SourceFile: "Dog.java"
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             //  playground/Dog
   #2 = Utf8               playground/Dog
   #3 = Class              #4             //  java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               dog
   #6 = Utf8               Lplayground/Dog;
   #7 = Utf8               val1
   #8 = Utf8               I
   #9 = Utf8               ConstantValue
  #10 = Integer            -5
  #11 = Utf8               val2
  #12 = Utf8               val3
  #13 = Utf8               <clinit>
  #14 = Utf8               ()V
  #15 = Utf8               Code
  #16 = Methodref          #1.#17         //  playground/Dog."<init>":()V
  #17 = NameAndType        #18:#14        //  "<init>":()V
  #18 = Utf8               <init>
  #19 = Fieldref           #1.#20         //  playground/Dog.dog:Lplayground/Dog;
  #20 = NameAndType        #5:#6          //  dog:Lplayground/Dog;
  #21 = Fieldref           #1.#22         //  playground/Dog.val2:I
  #22 = NameAndType        #11:#8         //  val2:I
  #23 = Utf8               LineNumberTable
  #24 = Utf8               LocalVariableTable
  #25 = Methodref          #3.#17         //  java/lang/Object."<init>":()V
  #26 = Fieldref           #1.#27         //  playground/Dog.val3:I
  #27 = NameAndType        #12:#8         //  val3:I
  #28 = Utf8               this
  #29 = Utf8               main
  #30 = Utf8               ([Ljava/lang/String;)V
  #31 = Fieldref           #32.#34        //  java/lang/System.out:Ljava/io/PrintStream;
  #32 = Class              #33            //  java/lang/System
  #33 = Utf8               java/lang/System
  #34 = NameAndType        #35:#36        //  out:Ljava/io/PrintStream;
  #35 = Utf8               out
  #36 = Utf8               Ljava/io/PrintStream;
  #37 = Methodref          #38.#40        //  java/io/PrintStream.println:(I)V
  #38 = Class              #39            //  java/io/PrintStream
  #39 = Utf8               java/io/PrintStream
  #40 = NameAndType        #41:#42        //  println:(I)V
  #41 = Utf8               println
  #42 = Utf8               (I)V
  #43 = Utf8               args
  #44 = Utf8               [Ljava/lang/String;
  #45 = Utf8               SourceFile
  #46 = Utf8               Dog.java
{
  public static playground.Dog dog;
    flags: ACC_PUBLIC, ACC_STATIC


  static final int val1;
    flags: ACC_STATIC, ACC_FINAL
    ConstantValue: int -5


  static int val2;
    flags: ACC_STATIC


  public int val3;
    flags: ACC_PUBLIC


  static {};
    flags: ACC_STATIC
    Code:
      stack=2, locals=0, args_size=0
         0: new           #1                  // class playground/Dog
         3: dup           
         4: invokespecial #16                 // Method "<init>":()V
         7: putstatic     #19                 // Field dog:Lplayground/Dog;
        10: iconst_3      
        11: putstatic     #21                 // Field val2:I
        14: return        
      LineNumberTable:
        line 4: 0
        line 6: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature

  public playground.Dog();
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0       
         1: invokespecial #25                 // Method java/lang/Object."<init>":()V
         4: aload_0       
         5: bipush        -5
         7: getstatic     #21                 // Field val2:I
        10: iadd          
        11: putfield      #26                 // Field val3:I
        14: return        
      LineNumberTable:
        line 8: 0
        line 9: 4
        line 10: 14
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      15     0  this   Lplayground/Dog;

  public static void main(java.lang.String[]);
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #31                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: getstatic     #19                 // Field dog:Lplayground/Dog;
         6: getfield      #26                 // Field val3:I
         9: invokevirtual #37                 // Method java/io/PrintStream.println:(I)V
        12: return        
      LineNumberTable:
        line 12: 0
        line 13: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      13     0  args   [Ljava/lang/String;
}

Let’s illustrate the whole process using pictures:

 

The following is a complicated example:

public class Test {

    private static int k = 1;
    private static Test t1 = new Test("t1");
    private static Test t2 = new Test("t2");
    private static int n = 99;
    private static int j = print("j");

    private int i = print("i");

    {
        print("构造块");
    }

    static {
        print("静态构造块");
    }

    public Test(String str) {
        System.out.println((++k) + ":" + str +"  j="+j+" n="+n);
        ++j;
        ++n;
    }

    public static int print(String str) {
        System.out.println((++k) + ":" + str +"  j="+j+" n="+n);

        ++n;
        return ++j;
    }

    public static void main(String[] args) {

    }
}

the result is:

2:i j=0 n=0 3:构造块 j=1 n=1 4:t1 j=2 n=2 5:i j=3 n=3 6:构造块 j=4 n=4 7:t2 j=5 n=5 8:j j=6 n=99 9:静态构造块 j=7 n=100