繁体   English   中英

从实例初始化程序更新静态final字段

[英]Updating a static final field from an instance initializer

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

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

先感谢您!

对成员方法的调用是否构成“冻结操作”,或者它是否指示JVM对于所有意图和目的,“初始化”对象是什么? 好奇为什么这会产生影响。

问题是你的课程是从上到下初始化的。 这意味着您的静态字段尚未初始化,即您的Map为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字段,但除非没有其他选项,否则应该避免这样做。

执行您要执行的操作的正确方法是编写静态初始化程序,该程序创建所有枚举之后运行。

防御性编程:您还应该添加一个简单的检查以防止编程错误。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM