静态初始化程序未在活动创建时调用

时间:2016-02-09 16:53:36

标签: java android static

我的主要活动中有以下代码:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Fabric.with(this, new Crashlytics());
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        MyClass[] arr = MyClass.values();
        System.out.println(Arrays.deepToString(arr));

MyClass如下:

public class MyClass {

    public static MyClass A;
    public static MyClass B;
    public static MyClass C;

    static {
        System.out.println("Invoked");
        A = new MyClass("a");
        B = new MyClass("b");
        C = new MyClass("c");
    }

    private static Map<String, MyClass> values = null;
    private final String name;

    private MyClass(String name) {
        this.name = name;
        if (values == null)
            values = new HashMap<>();
        values.put(name, this);
    }

    public static MyClass[] values() {
        return values.values().toArray(new MyClass[values.size()]);
    }
}

我的问题是values()触发NullPointerException,因为values为空,即静态初始化块似乎不会被调用。然而,控制台输出“Invoked”,所以初始化块被调用。

怎么了?

编辑:这个问题与此严格相关:Issue with static code in Android

1 个答案:

答案 0 :(得分:4)

这是因为private static Map<String, MyClass> values = null;位于静态初始化程序之后:此赋值将在静态初始化程序块之后运行,因此它被赋予非空值,然后被清空。

在初始化程序段之前移动values字段。

顺便说一下,我会将实例的创建与将它们插入地图分开,以便在创建MyClass实例时消除副作用。您也可以在没有静态初始化程序块的情况下执行此操作:

public class MyClass {
    private static final Map<String, MyClass> values = new HashMap<>();

    public static final MyClass A = register(new MyClass("a"));
    public static final MyClass B = register(new MyClass("b"));
    public static final MyClass C = register(new MyClass("c"));

    private static MyClass register(MyClass instance) {
      values.put(instance.name, instance);
      return instance;
    }

    private MyClass(String name) {
      this.name = name;
    }
    // ...
}

实际上,我甚至不会这样做:我会使用enum - 但我猜你的真实代码中有一些东西阻止你这样做。