Java禁止从初始化程序访问最终的静态字段。例如:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
Example.exampleByPropertyA.put(propertyA, this); // <- Not permitted
}
}
但是,如果静态Map
的更新是在初始化程序调用的单独方法中执行的,那么这很好。例如:
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
addExample(this);
}
private addExample(Example example) {
Example.exampleByPropertyA.put(example.propertyA, example); // <- Permitted
}
}
鉴于此上下文,我的问题是:对成员方法的调用是否构成“冻结操作”,或者它是否指示JVM对于所有意图和目的,“初始化”对象是什么?好奇为什么会有所作为。
我已经做了一些搜索,但没有找到任何清楚表达的东西。
提前谢谢!
答案 0 :(得分:2)
对成员方法的调用是否构成“冻结操作”,还是指示JVM对于所有意图和目的,该对象是“初始化”的?好奇为什么会有所作为。
问题是你的课程是从上到下初始化的。这意味着您的静态字段尚未初始化,即您的地图为null
。
另一种方法是添加一个静态初始化块,以便在所有内容初始化后调用。
static {
for (Example e: values()) {
addExample(e);
}
}
private static addExample(Example example) {
Example prev = exampleByPropertyA.put(example.propertyA, example);
assert prev == null;
}
注意:您可以在初始化之前看到最终变量。这意味着即使不使用反射,final
也可以具有前后值。
public class A {
final String text = getText();
private String getText() {
System.out.println("text= " + text);
return "is set";
}
public static void main(String... args) {
new A().getText();
}
}
打印
text= null
text= is set
使用反射即使在初始化之后也可以更改final
字段,但除非没有其他选项,否则应该避免这样做。
答案 1 :(得分:2)
执行您要执行的操作的正确方法是编写静态初始化程序,在创建所有枚举后运行。
防御性编程:您还应该添加一个简单的检查以防止编程错误。
public enum Example {
ValueA("valueAA", "valueAB"),
ValueB("valueBA", "valueBB");
final static Map<String, Example> exampleByPropertyA = new HashMap<>();
static {
for (Example ex : values())
if (exampleByPropertyA.put(ex.propertyA, ex) != null)
throw new IllegalStateException("Duplicate propertyA: " + ex.propertyA);
}
final String propertyA;
final String propertyB;
Example(String propertyA, String propertyB) {
this.propertyA = propertyA;
this.propertyB = propertyB;
}
}