枚举中的非法前向引用
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;
}
}
我该如何解决?谢谢
有两种可能的解决方案对我来说似乎是合理的。
使用嵌套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; }
}
这是最常用的,因为它没有强加任何重要限制。
使用方法:
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
我有一个枚举,我正在尝试将最终静态变量作为构造函数中的参数传递。问题是枚举中的第一个语句必须是实例本身,但在这种情况下,最终变量尚未定义。看代码你就明白了:
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;
}
}
我该如何解决?谢谢
有两种可能的解决方案对我来说似乎是合理的。
使用嵌套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; } }
这是最常用的,因为它没有强加任何重要限制。
使用方法:
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 otherstatic
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 otherstatic
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