Java编译器数据流分析出现异常误报

3

我有以下形式的代码:

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-style循环
这里发生了什么?
注意:我无法让最小示例引发错误,因此“环境”(约1400个loc)可能有问题。 但是,我看不出会干扰t的初始化的原因,因为t没有被写入任何其他地方。
有趣的事实:如果我移除final修饰符,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上可以。所以我想我遇到了一些奇怪的边角情况,还是什么问题吗?

请注意,您可以执行以下任何操作:

  • 删除任何一个成员
  • A()中移除循环内的final
  • 用普通的for循环替换循环,例如for ( int i=0; i<100; i++ ) { ... }

它将会被编译。


你可能有自定义编译器设置,你使用的是哪个IDE? - Kai
我运行了 mvn install 命令;我们的项目没有定义编译器参数(据我所知)。 - Raphael
对我来说似乎是IntelliJ的问题。Eclipse对我来说没有出现这个问题。当然,如果循环没有引用“t”,那么它以后不应该受到影响。 - Gray
CLI Maven 显示错误。我同意它不应该出现,但它确实出现了。 - Raphael
4个回答

1
如果你有很多代码,我建议试试这个。
private final A t;

public Test() {
    final int t = 1;

   for ( ... ) {
      final A u = null;
   }

   this.t = new A();

这将导致任何“可能”初始化t的代码失败(并在编译器中显示)。


正如我在问题中所述,没有其他对Test#t的写入。我通过使用搜索、字符串搜索和——只是为了逗你——按照你的建议引发编译器错误来确认这一点。 - Raphael

1

由于问题在Java 7中已经得到解决,因此很可能是Java 6编译器中的一个错误。


1

如果你的构造函数恰好调用另一个没有设置t的构造函数,编译器将无法理解。

请参见这里


谢谢你的回答。我也考虑过这个,但是没有这样的调用。事实上,我只定义了这一个构造函数。我的真正类是顶级的,不扩展任何其他类(但是扩展了Object),所以在这方面不应该有任何干扰。它实现了一个接口,但这不应该有影响。 - Raphael
@Raphael 我猜你最好提供一个SSCCE,当然它不应该编译... 在IntelliJ中编译得很好。 - yair
如果我知道关键部分,我就会知道问题了,你不觉得吗? ;) 我不明白外部的东西怎么会影响到这个问题,所以我不知道从哪里开始添加/删除东西。不过我正在努力尝试。 - Raphael
我花了一些时间,但现在我有一个小例子了。请参见上文。 - Raphael

-2

我的理解是将一个对象存储在final变量中并不会使它成为不可变的,但是其引用会被设置为不可变。这就解释了为什么当您删除final关键字时,程序仍然可以工作。至于删除for循环部分,我认为您访问的是对象引用而不是实例本身。


在一个简化的代码中,u 在初始化后从未被访问或写入(该代码仍无法编译)。 - Raphael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接