Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java initialization order issue, static vs instance fields

Tags:

java

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);
    }
}
like image 858
Eleco Avatar asked Mar 11 '10 07:03

Eleco


3 Answers

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:

  • Load class SomeClass, all static fields initially defaults (0, null, etc.)
  • Begin static inits
  • First static init creates instance of SomeClass
  • Begin instance inits for SomeClass instance, using current values for static fields (so objectName1 and objectName2 are null)
  • Load SomeObject class, all static fields initially default (you don't have any)
  • Do SomeObject static inits (you don't have any)
  • Create instances of SomeObject using the passed-in null values
  • Continue static inits of SomeClass, 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.

like image 195
T.J. Crowder Avatar answered Sep 21 '22 18:09

T.J. Crowder


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.

like image 27
kukudas Avatar answered Sep 20 '22 18:09

kukudas


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
}
like image 28
sfussenegger Avatar answered Sep 22 '22 18:09

sfussenegger