枚举中的非法前向引用

Illegal forward reference in enum

我有一个枚举,我正在尝试将最终静态变量作为构造函数中的参数传递。问题是枚举中的第一个语句必须是实例本身,但在这种情况下,最终变量尚未定义。看代码你就明白了:

public enum ParseResource {

    PUSH(API_URL); //Error: illegal forward reference

    private final static String API_URL = "https://api.parse.com/1";

    private String url;
    private ParseResource(String url) {
        this.url = url;
    }
}

和另一个选项:

public enum ParseResource {

    //Illegal in enums, first statement has to be an instance
    private final static String API_URL = "https://api.parse.com/1";

    PUSH(API_URL);

    private ParseResource(String url) {
        this.url = url;
    }
}

我该如何解决?谢谢

有两种可能的解决方案对我来说似乎是合理的。

  1. 使用嵌套class(单独初始化):

    public enum ParseResource {
        PUSH(Constants.API_URL);
    
        private static class Constants {
            private static final String API_URL = "https://api.parse.com/1";
        }
    
        private String url;
        private ParseResource(String url) { this.url = url; }
    }
    

    这是最常用的,因为它没有强加任何重要限制。

  2. 使用方法:

    public enum ParseResource {
        PUSH(getApiUrl());
    
        private static String getApiUrl() { return "https://api.parse.com/1"; }
    
        private String url;
        private ParseResource(String url) { this.url = url; }
    }
    

    使用方法的一个隐藏缺点是方法调用不是 constant expression,因此它不能用于某些事情,例如注释元素值。


还有第三种可能的方法在实践中起作用,但是从 Java 9 开始,JLS 不再保证工作,所以它不应该被使用。

这使用限定名称 ParseResource.API_URL 而不是简单名称 API_URL 来规避前向引用错误,因为 API_URL 是一个 constant variable (即用一个String 在本例中为文字):

public enum ParseResource {
    PUSH(ParseResource.API_URL);

    private static final String API_URL = "https://api.parse.com/1";

    private String url;
    private ParseResource(String url) { this.url = url; }
}

在 Java 8 中,此 的良好行为是由 8.3.2 指定的 :

Note that static fields that are constant variables are initialized before other static fields. [...] Such fields will never be observed to have their default initial values.

然而,due to this bug report, the wording was changed to the following in Java 9:

Note that static fields that are constant variables are initialized before other static fields. [...] When such fields are referenced by simple name, they will never be observed to have their default initial values.

以上代码不受错误报告中描述的缺陷的影响,但从 Java 9 开始,它不再保证工作。

枚举是语法糖,基本上可以让您编写更好的 switch 语句以及迭代某个 class.

的编译时值集

在这种情况下,您可以在 class 中定义编译时字符串,例如 Constants - 当您遇到此类编译问题时,一般规则是您不应该使用枚举方式和需要其他 classes