简体   繁体   English

javac数据流分析的奇怪误报

[英]Weird false-positive of javac data flow analysis

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 将循环的内容更改为A u = null
  • Remove the loop (but keep final A u = null; ) 删除循环(但保持final A u = null;
  • Replace the foreach-style loop with a classic counting loop 用经典的计数循环替换foreach风格的循环

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). 注意:我无法得到导致错误的最小示例,因此“环境”(大约1400 loc)可能存在问题。 I can not see what could disturb the initialisation of t , though, as t is written to nowhere else. 然而,我无法看到可能会扰乱t初始化的因素,因为t被写入其他地方。

Fun fact: IntelliJ IDEA says "Variable 'u' can have 'final' modifier..." if I remove it. 有趣的事实:IntelliJ IDEA说“变量'你可以拥有'最终'修饰符......”如果我删除它。

I use javac 1.6.0_26. 我使用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 . 无法在javac 1.6.0_26编译,但在javac 1.7.0_02javac 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 in A() A()删除循环内的final
  • Replace the loop with a normal for loop, eg for ( int i=0; i<100; i++ ) { ... } 用普通的for循环替换循环,例如for ( int i=0; i<100; i++ ) { ... }

and it will compile. 它会编译。

If you have lots of code I would try this. 如果你有很多代码我会尝试这个。

private final A t;

public Test() {
    final int t = 1;

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

   this.t = new A();

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. 如果你的构造函数恰好调用另一个本身不设置t构造函数,编译器就无法理解。

See here . 看到这里

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

It is my understanding that storing an object in a final var does not make your object immutable but its reference. 我的理解是,在最终的var中存储一个对象并不会使你的对象成为不可变的,而是它的引用。 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. 这解释了为什么当你删除它工作的最终关键字时,并且因为删除for循环,我认为你正在访问对象引用而不是实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM