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, instance blocks and fields second. Therefore variables "objectName1" and "objectName2" should be initialized first, instance variable "list" second...but the ouput obviously contradicts this theory... Can anyone explain the program behavior (I'm not looking for a critique of the design in itself btw) ?
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);
}
}
Static blocks are initialized in order (so you can rely on the ones above in the ones below). By creating an instance of SomeClass
as your first static initializer in SomeClass
, you're forcing an instance init during the static init phase.
So the logical order of execution of your code is:
SomeClass
, all static fields initially defaults (0
, null
, etc.)SomeClass
SomeClass
instance, using current values for static fields (so objectName1
and objectName2
are null
)SomeObject
class, all static fields initially default (you don't have any)SomeObject
static inits (you don't have any)SomeObject
using the passed-in null
valuesSomeClass
, setting objectName1
and objectName2
To make this work as you may expect, simply put the inits for objectName1
and objectName2
above the init for instance
.
As suggested moving this line:
private static final SomeClass instance = new SomeClass();
after these:
private static String objectName1 ="test1";
private static String objectName2 ="test2";
should fix the problem.
On first look I was pretty surprised about the behavior myself, but on second thought, it is quite trivial to explain:
private static final SomeClass instance = new SomeClass();
is part of the static initialization of SomeClass
. As you create an instance before initialization has completed, the class is not yet completely initialized. When you replace the System.out.println(...);
with something like new Exception().printStackTrace();
you get this (note that I put all classes as static nested classes into 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 see, execution still is inside Main$SomeClass.<clinit>
(the class initialization), hence SomeClass is not completely initialized.
As a side note: the best way to implement Singleton pattern is to avoid it completely. The second best most likely is using enum
(at least it's Josh-Bloch-approved)
class enum SomeClass {
instance;
// snip
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With