Java 从实例初始值设定项更新静态最终字段

Java 从实例初始值设定项更新静态最终字段,java,Java,Java禁止从初始值设定项访问最终静态字段。例如: public enum Example { ValueA("valueAA", "valueAB"), ValueB("valueBA", "valueBB"); final static Map<String, Example> exampleByPropertyA = new HashMap<>(); final String propertyA; final String

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
    }
}
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表明该对象在所有意图和目的下都是“初始化的”?我很好奇为什么这会有不同

问题是您的类是从上到下初始化的。这意味着您的静态字段尚未初始化,即您的映射为
null

另一种方法是添加一个静态初始化块,在初始化所有内容后调用

static {
    for (Example e: values()) {
        addExample(e);
    }
}

private static addExample(Example example) {
    Example prev = exampleByPropertyA.put(example.propertyA, example);
    assert prev == null;
}

注意:您可以在初始化前查看最终变量。这意味着即使不使用反射,
final
也可以有一个before和after值

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;
    }
}
公共枚举示例{
ValueA(“valueAA”、“valueAB”),
ValueB(“valueBA”、“valueBB”);
最终静态映射exampleByPropertyA=newHashMap();
静止的{
例如(例如ex:values())
if(exampleByPropertyA.put(ex.propertyA,ex)!=null)
抛出新的IllegalStateException(“复制属性a:+ex.propertyA”);
}
最终字符串属性a;
最终字符串属性b;
示例(字符串属性a、字符串属性b){
this.propertyA=propertyA;
this.propertyB=propertyB;
}
}

你所说的“冻结行动”是什么意思?你是说一个“阻塞”方法调用吗?不,我说的是最后一个字段冻结操作。@sellc有趣的是,我以前从未遇到过这个问题。谢谢你的链接。哦,太棒了。天哪。我知道这一点,但我没有在列举时考虑到这一点。再过8分钟左右我就不能接受你的回答了,但这完全有道理。我知道我必须忽视这样的事情。非常感谢。“final”变量的值不能更改或更新,@SAMUELMARCHANT-是的,我理解这一点,但如果深入研究Java内存模型,您会发现某些东西会调用这些最终值的“冻结”。在此类冻结操作之后初始化的最终值不一定是“最终值”。@SAMUELMARCHANT static Final可以在初始化之前访问。+1用于从“防御性编码”的角度进行说明。这两个答案都很有道理,但我会接受彼得的答案,因为他是第一个得到答案的。感谢不过,感谢您的及时回复@但是我的代码是完整的,而Peter的代码缺少
addExample
,并且不能使用您的代码,因为您的代码不是静态的。--不,很好。你接受你最喜欢的答案。;-)我的观点是正确的,但该方法在我的示例中已经定义,所以它是有意义的。没有怨恨!:)不确定这是否值得一个可捕获的
非法状态异常
我会使用断言错误。