簡體   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