我的主要活动中有以下代码:
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
答案 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
- 但我猜你的真实代码中有一些东西阻止你这样做。