javac数据流分析的奇怪误报
我有以下形式的代码:
class Test {
private final A t;
public Test() {
for ( ... : ... ) {
final A u = null;
}
t = new A();
}
private class A {}
}
编译器说:
variable t might already have been assigned
有趣的是,如果我对循环执行以下任何更改,它就会起作用!
- 将循环的内容更改为
A u = null
- 删除循环(但保留
final A u = null;
) - 将 foreach 样式的循环替换为经典的计数
循环在这里?
注意:我无法获得导致错误的最小示例,因此“环境”(大约 1400 loc)可能有问题。不过,我看不出什么会干扰 t
的初始化,因为 t
没有写入其他地方。
有趣的事实:如果我删除它,IntelliJ IDEA 会说“变量 'u' 可以有 'final' 修饰符...”。
我使用javac 1.6.0_26。
更新:就是这样,这个示例非常如此:
import java.util.List;
class A {
private final boolean a;
public A() {
for ( final Object o : new Object[] {} ) {
final Object sh = null;
}
a = true;
}
class B {
private final Object b1;
private final Object b2;
B() {
b1 = null;
b2 = null;
}
}
}
无法在 javac 1.6.0_26
上编译,但可以在 javac 1.7 上编译。 0_02
。所以我想我遇到了一些邪恶的极端情况......什么?
删除 final
中的任何操作,
- 执行删除任何一个成员
- 请注意,您可以在
A()
中的循环内 - 将循环替换为普通的
for
循环,例如for ( int i=0; i<100; i++ ) { ... }
它将编译。
I have code of the following form:
class Test {
private final A t;
public Test() {
for ( ... : ... ) {
final A u = null;
}
t = new A();
}
private class A {}
}
Compiler says:
variable t might already have been assigned
Interestingly, if I perform any of the following changes to the loop it works out!
- Change the loop's content to
A u = null
- Remove the loop (but keep
final A u = null;
) - Replace the foreach-style loop with a classic counting loop
What is going on here?
Note: I could not get the minimal example to cause the error so there is probably something wrong with the "environment" (about 1400 loc). I can not see what could disturb the initialisation of t
, though, as t
is written to nowhere else.
Fun fact: IntelliJ IDEA says "Variable 'u' can have 'final' modifier..." if I remove it.
I use javac 1.6.0_26.
Update: There you go, this example so so minimal:
import java.util.List;
class A {
private final boolean a;
public A() {
for ( final Object o : new Object[] {} ) {
final Object sh = null;
}
a = true;
}
class B {
private final Object b1;
private final Object b2;
B() {
b1 = null;
b2 = null;
}
}
}
Fails to compile on javac 1.6.0_26
but compiles on javac 1.7.0_02
. So I guess I hit some wicked corner case of ... something?
Note that you can do any of
- Remove any one member
- Remove
final
inside the loop inA()
- Replace the loop with a normal
for
loop, e.g.for ( int i=0; i<100; i++ ) { ... }
and it will compile.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
如果你有很多代码我会尝试这个。
这将导致任何“可能”初始化
t
的代码失败(并显示在编译器中)。If you have lots of code I would try this.
This will cause any code which "might" initialise
t
to fail (and show up in the compiler.如果您的构造函数碰巧调用了另一个本身未设置 t 的构造函数,则编译器将无法理解这一点。
请参阅此处。
If you're constructor happen to call another constructor that doesn't itself set
t
, the compiler fails to understand that.See here.
由于该问题在 Java 7 中已得到解决,因此它可能是 Java 6 编译器中的一个错误。
As the problem is fixed in Java 7, it is probably a bug in the Java 6 compiler.
据我了解,将对象存储在最终变量中并不会使您的对象不可变,而是使其引用不可变。这就解释了为什么当您删除final关键字时它会起作用,并且根据删除for循环,我认为您正在访问对象引用而不是实例。
It is my understanding that storing an object in a final var does not make your object immutable but its reference. That explain why when you remove the final keyword it works and as per removing the for-loop, i think you are accessing the object reference and not an instance.