Problem Reproduction
Let's take a look at the following program:
1 public class StaticInitSequence {
2 // ------------------- Static fields -------------------
3 private static int staticIntVar = 10;
4 private static int staticComputeIntVar = (int) (Math. random () * 10 );
5 private static String staticStrVar = "Static field init (before )";
6 private static Object staticRefVar = new Object ();
7
8 static {
9 staticIntVar = 20;
10 staticStrVar = "Static block init (before )";
11 staticAfterIntVar = 40;
12 staticAfterStrVar = "Static block init (after )";
13}
14
15 private static int staticAfterIntVar = 30;
16 private static String staticAfterStrVar = "Static field init (after )";
17
18 // --------------------- Instance fields ----------------
19 private int fieldIntVar = 100;
20 private int fieldComputeIntVar = (int) (Math. random () * 100 );
21 private String fieldStrVar = "Instance field init (before )";
22
23 public StaticInitSequence (){
24 fieldIntVar = 200;
25 fieldStrVar = "Constructor field init (before )";
26
27 fieldAfterIntVar = 400;
28 fieldAfterStrVar = "Constructor field init (after )";
29}
30
31. private int fieldAfterIntVar = 300;
32 private String fieldAfterStrVar = "Instance field init (after )";
33
34 public void print (){
35 System. out. println ("---------------- Static Fields ------------");
36 System. out. println ("staticIntVar:" + staticIntVar );
37 System. out. println ("staticComputeIntVar:" + staticComputeIntVar );
38 System. out. println ("staticStrVar:" + staticStrVar );
39 System. out. println ("staticRefVar:" + staticRefVar );
40 System. out. println ("staticAfterIntVar:" + staticAfterIntVar );
41 System. out. println ("staticAfterStrVar:" + staticAfterStrVar );
42
43 System. out. println ("----------------- Instance Fields ---------");
44 System. out. println ("fieldIntVar:" + fieldIntVar );
45 System. out. println ("fieldComputeIntVar:" + fieldComputeIntVar );
46 System. out. println ("fieldStrVar:" + fieldStrVar );
47 System. out. println ("fieldAfterIntVar:" + fieldAfterIntVar );
48 System. out. println ("fieldAfterStrVar:" + fieldAfterStrVar );
49}
50}
What will happen if we call the print () method (new StaticInitSequence (). print () of the preceding class?
In my opinion, initializing a field directly is a programming method supported by the compiler. This programming method can improve the readability of the Code, because you can directly know the initial value of a field, instead of looking for it in the constructor or static statement block. In Java, In the compiled binary file, all the field initialization statements are placed in the initialization function (Class (static) initialization function (<clinit>) or the instance initialization (constructor/<init>) function ). Therefore, in my logic thinking, in the source code, the initialization function should be able to change the value in the field initialization, so that an initial value can be provided in the field initialization, in the initialization function, change it as needed. However, I am surprised that only the instance initialization mechanism in Java is implemented in this way, this mechanism is not implemented in static field initialization (this mechanism is implemented in C # Regardless of instance initialization and static initialization ), the initialization sequence of static fields is fully initialized according to the defined sequence in the source code. From the coupling perspective, this is a typical type of sequential coupling. I don't know why Java is implemented like this. Is there any other considerations? Or a mistake made by the Java designer or the Java compiler designer? In any case, the running results of the above programs compiled with sun's javac are as follows:
---------------- Static Fields ------------
StaticIntVar: 20
StaticComputeIntVar: 7
StaticStrVar: Static block init (before)
StaticRefVar: java. lang. Object @ 14318bb
StaticAfterIntVar: 30
StaticAfterStrVar: Static field init (after)
--------------- Instance Fields ---------
FieldIntVar: 200
FieldComputeIntVar: 8
FieldStrVar: Constructor field init (before)
FieldAfterIntVar: 400
FieldAfterStrVar: Constructor field init (after)
Explanation:
From the binary code generated by the above program, the above results can be well explained:
<Clinit>:
// StaticIntVar = 10
0 bipush 10
2 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticIntVar: int [22]
// StaticComputeIntVar = (int) (Math. random () * 10)
5 invokestatic java. lang. Math. random (): double [24]
8 ldc2_w <Double 10.0> [30]
11 dmul
12 d2i
13 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticComputeIntVar: int [32]
// StaticStrVar = "Static field init (before )"
16 ldc <String "Static field init (before)"> [34]
18 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticStrVar: java. lang. String [36]
// StaticRefVar = new Object ();
21 new java. lang. Object [3]
24 dup
25 invokespecial java. lang. Object () [38]
28 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticRefVar: java. lang. Object [41]
// StaticIntVar = 20
31 bipush 20
33 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticIntVar: int [22]
// StaticStrVar = "Static block init (before )"
36 ldc <String "Static block init (before)"> [43]
38 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticStrVar: java. lang. String [36]
// StaticAfterIntVar = 40
41 bipush 40
43 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticAfterIntVar: int [45]
// StaticAfterStr = "Statci block init (after )"
46 ldc <String "Static block init (after)"> [47]
48 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticAfterStrVar: java. lang. String [49]
// StaticAfterIntVar = 30
51 bipush 30
53 putstatic org. levin. insidejvm. miscs. staticinit. StaticInitSequence. staticAfterIntVar: int [45]
// StaticAfterStrVar = "Static field init (after )"
56 ldc <String "Static field init (after)"> [51]
58 putstatic org. levin. insidejvm.