繁体   English   中英

无法编译调用自身的runnable吗?

[英]Can't compile runnable that calls itself?

我正在尝试制作一个可调用自身的Runnable

class A {
  public void f() {
    final Runnable r = new Runnable() {
      public void run() {
        // do stuff, return if it worked.
        r.run(); // otherwise try again
      }
    };
  }
}

它得到此错误:

$ javac A.java
A.java:6: error: variable r might not have been initialized
        r.run(); // otherwise try again
        ^
1 error

为什么? Runnable的标准库定义中是否有什么特别之处,它消除了保证在使用接口实现之前对其进行了完全定义的保证(例如,当您实现该接口实现时,它就会运行一些代码)?

无法编译调用自身的runnable吗?

您可以-只是不用用r限定run()方法的名称; 您可以明确地引用其内部的方法:

class A {
  public void f() {
    final Runnable r = new Runnable() {
      public void run() {
        ...
        run();  // notice that there is no `r.`
      }
    };
  }
}

代码中的问题是,您试图在变量r完全初始化之前使用它。 有点像:

int x = x;

当然哪个无效(并产生相同的错误消息)。

这与Runnable无关。 而是,导致此编译器错误,因为赋值右侧的表达式发生赋值之前

在这种情况下,编译器没有一种简单的方法来知道是否/在实际执行变量表达式时确实分配了 r ,从而完全禁止访问。

在访问任何值时 ,每个局部变量(第14.4节)和最后一个空白字段(第4.12.4节,第8.3.1.2节)都必须具有一个明确分配的值。

请考虑以下说明问题的内容,并且由于与最初发布的示例相同的编译器错误而失败。

final String r = (new Object() {
    public String toString() {
        // -> error: variable r might not have been initialized
        // (And in this case it is indeed *not* assigned!)
        return "Hello " + r + "!";
    }
}).toString();

回复狗的评论:

..当我今天遇到错误时,这正是我的想法。 但是我无法想到为什么它不仅仅假设在定义接口实现时就定义了r。

在上面的示例中,显示了在分配变量r之前肯定访问变量r情况。 同样,如果构造函数调用了虚拟方法(例如run ),则可以在分配它之前对其进行访问-但这种情况在整个编译单元中都无法检测到。

这是进一步问题的final和匿名访问类型:Java 没有在最后的变量创建一个闭包,但是当它创建匿名类型的实例,而结合这些变量的值 这将在对变量的访问(实际上是对先前绑定的值的访问)与匿名实例的创建之间创建无效的循环关系。

您可以保存此指针,然后在新的Runnable中调用Run方法:

    Runnable r = new Runnable() {
        @Override public void run() {
            // if condition met and need to run more
            final Runnable that = this;
            executor.execute(new Runnable() { @Override public void run() { that.run(); } });
        }
    };

暂无
暂无

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

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