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 风格的循环

这里发生了什么?

注意:我无法获得导致错误的最小示例,因此“环境”(大约 1400 位置)可能有问题。但是,我看不出有什么会干扰 的初始化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++ ) { ... }

它会编译。

4

4 回答 4

1

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

private final A t;

public Test() {
    final int t = 1;

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

   this.t = new A();

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

于 2012-02-02T13:21:30.210 回答
1

如果你的构造函数碰巧调用了另一个本身没有设置t的构造函数,编译器就无法理解这一点。

这里

于 2012-02-02T13:29:36.877 回答
1

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

于 2012-02-06T10:36:42.167 回答
-2

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

于 2012-02-02T13:36:46.057 回答