Java initialization order error, static instance fields vs

The program below prints:

my name is:null my name is:null Someclass static init 

AFAIK, when a class is first loaded, static blocks and fields are always initialized first, block instances and fields are second. Therefore, the variables "objectName1" and "objectName2" must be initialized first, the instance variable "list" second ... but the output obviously contradicts this theory ... Can anyone explain the behavior of the program (I am not looking for a critical analysis of the design myself btw itself)?

 import java.util.ArrayList; import java.util.List; public class Main2{ public static void main (String[] args){ SomeClass.getInstance(); } } class SomeClass { private static final SomeClass instance = new SomeClass(); public static SomeClass getInstance(){ return instance; } static { System.out.println ("Someclass static init"); } private static String objectName1 ="test1"; private static String objectName2 ="test2"; @SuppressWarnings("serial") private List<SomeObject> list= new ArrayList<SomeObject> () { { add (new SomeObject(objectName1)); add (new SomeObject(objectName2)); }}; } class SomeObject { String name; SomeObject (String name){ this.name = name; System.out.println ("my name is:" +name); } } 
+7
java
Mar 11 2018-10-11T00:
source share
4 answers

Static blocks are initialized in order (so you can rely on the ones above). By creating an instance of SomeClass as your first static initializer in SomeClass , you force an init instance during the static initialization phase.

So, the logical order of your code is:

  • Download the SomeClass class, all default static fields by default ( 0 , null , etc.)
  • Start static inits
  • The first static init creates an instance of SomeClass
  • Start instance instances for SomeClass instance using current values ​​for static fields (therefore objectName1 and objectName2 are null )
  • Download the SomeObject class, all static fields are initially the default (you don't have them)
  • Make SomeObject static inits (you don't have one)
  • Create SomeObject instances using past null values
  • Continue the static values ​​of SomeClass by setting objectName1 and objectName2

To make this work as you might expect, just put inits for objectName1 and objectName2 over init for instance .

+10
Mar 11 2018-10-10T00:
source share

As suggested by moving this line:

 private static final SomeClass instance = new SomeClass(); 

after that:

 private static String objectName1 ="test1"; private static String objectName2 ="test2"; 

should fix the problem.

+1
Mar 11 '10 at 8:10
source share

At first glance, I was very surprised by the behavior itself, but, on the other hand, it’s quite simple to explain:

 private static final SomeClass instance = new SomeClass(); 

is part of SomeClass static initialization. When you instantiate before initialization is complete, the class is not yet fully initialized. When you replace System.out.println(...); something like new Exception().printStackTrace(); you get this (note that I put all the classes as static nested classes in Main)

 at Main$SomeObject.<init>(Main.java:37) // new Exception().printStackTrace(); at Main$SomeClass$1.<init>(Main.java:26) // add(new SomeObject(...)) at Main$SomeClass.<init>(Main.java:23) // list = new ArrayList() at Main$SomeClass.<clinit>(Main.java:10) // instance = new SomeClass() at Main.main(Main.java:6) // SomeClass.getInstance(); 

As you can see, the execution is still inside Main$SomeClass.<clinit> (class initialization), so SomeClass is not fully initialized.

As a side note: the best way to implement the Singleton pattern is to completely eliminate it. The second most likely option is to use enum (at least approved by Josh Bloch)

 class enum SomeClass { instance; // snip } 
+1
Mar 11 '10 at 8:12
source share

The first thing that is executed is probably the static initializer of the instance variable. This causes the list to be initialized using the variables (uninitialized) objectName1 and objectName2 . After that, he proceeds to initialize objectName1 and objectName2 .

If you move the instance declaration to the end of SomeClass , it will probably do what you expect.

0
Mar 11 '10 at 8:05
source share



All Articles