![](/img/trans.png)
[英]can't stop a Runnable that passing itself in ScheduledExecutorService.schedule
[英]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.