要区分实例字段和同名的本地变量,我们可以限定对前缀为this.
的字段的访问权限:
class Test {
public final Foo x;
public Test(Foo x) {
this.x = x;
}
}
我试图通过使用类名限定访问权限来在静态上下文中执行相同的操作:
import java.util.*;
class Test {
public static final Map<String,Object> map;
static {
Map<String,Object> map = new HashMap<>();
// ...
// assume I fill the map with useful data here
// ...
// now I want to freeze it and assign it to the field
Test.map = Collections.unmodifiableMap(map);
}
}
编译器不想与此代码有任何关系。我有几个像这样的变量,并且对于所有变量,它一直在大喊大叫:&#34;不能为最终变量分配值&#34;。如果我没有分配给它,它就会抱怨&#34;变量未初始化&#34;代替。如果我在开始时指定静态字段并尝试使地图不可修改,则会抱怨&#34;变量可能已经被分配了#34;。它对任何事情都不满意。
这是语言中的缺陷还是编译器中的错误?什么是压缩编译器执行操作的最佳方法?
答案 0 :(得分:5)
最简单的解决方法如下:
import java.util.*;
class Test {
public static final Map<String,Object> map;
static {
Map<String,Object> contents = new HashMap<>();
map = Collections.unmodifiableMap(contents);
}
}
不知怎的,如果你在Java 8中使用类名限定常量,编译器就不会拥有它。
<强>更新强>
经过一些挖掘,似乎Java Language Specification明确指出简单(不合格)名称需要用于最终字段的分配(突出显示我的):
对于局部变量或空白最终字段x的每次访问,x必须为 在访问之前明确分配,或发生编译时错误。
同样,每个空白的最终变量最多只能分配一次; 当它的赋值发生时,它必须是绝对未分配的。
这样的分配定义为当且仅当 变量的简单名称(或者,对于字段,其简单名称 由此限定)发生在作业的左侧 操作强>
答案 1 :(得分:1)
看起来好像可以说
public static final <something> x;
static {
x = <whatever>;
}
但不是
public static final <something> x;
static {
MyClass.x = <whatever>;
}
我不确定为什么,但这就是我得到的行为。要在您自己的示例中避免这种情况,只需将Test.map
更改为map
,然后更改其他map
变量的名称。
P.S。 Robby的回答解释了这种行为的原因。
答案 2 :(得分:0)
我实现了一种解决方法,使用一种方法来初始化字段而不是静态块。在方法内部,变量当然可以命名为它想要命名的foo:
public static final Map<String,Object> map = initMap();
private static Map<String,Object> initMap() {
...
}