javac数据流分析的奇怪误报

时间:2012-02-02 13:12:21

标签: java compiler-errors static-analysis javac dataflow

我有以下形式的代码:

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说“变量'你可以拥有'最终'修饰符......”如果我删除它。

我使用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++ ) { ... }

它将编译。

4 个答案:

答案 0 :(得分:1)

如果你有很多代码,我会尝试这个。

private final A t;

public Test() {
    final int t = 1;

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

   this.t = new A();

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

答案 1 :(得分:1)

如果您的构造函数碰巧调用了另一个本身不设置t的构造函数,则编译器无法理解。

请参阅here

答案 2 :(得分:1)

由于问题已在Java 7中修复,因此它可能是Java 6编译器中的一个错误。

答案 3 :(得分:-2)

我的理解是,将对象存储在final var中并不会使您的对象成为不可变的,而是它的引用。这解释了为什么当你删除它工作的最终关键字时,为了删除for循环,我认为你正在访问对象引用而不是实例。