从实例初始值设定项

时间:2018-04-11 23:16:47

标签: java

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对于所有意图和目的,“初始化”对象是什么?好奇为什么会有所作为。

我已经做了一些搜索,但没有找到任何清楚表达的东西。

提前谢谢!

2 个答案:

答案 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;
    }
}