Java Can';无法编译调用自身的可运行的?
我试图使一个Java Can';无法编译调用自身的可运行的?,java,variable-assignment,runnable,Java,Variable Assignment,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:
可运行的调用自身:
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
在分配之前肯定会被访问。同样,如果构造函数调用了一个虚拟方法(比如run
),那么在分配它之前就可以访问它——但是这种情况在编译单元中无法检测到
这对于匿名类型中的final
和访问来说是一个更大的问题:Java不会在final变量上创建闭包,而是在创建匿名类型的实例时绑定这些变量的值。这会在访问变量(实际上是访问以前绑定的值)和创建匿名实例之间创建无效的循环关系。您可以保存此指针并在新的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(); } });
}
};
您的代码示例有什么问题?它看起来应该对我有用。@Dog它不会编译,会导致错误:变量r可能没有初始化
。当你说“之前发生”时,你是在谈论共享内存上下文中使用的之前发生
的形式关系吗?是的,它不会编译,但我不明白为什么。不。这里没有并发问题。v
仅在赋值语句之后出现。这个错误就是因为这个原因而产生的。这种解决方法有一定的帮助,但是如果我在r内部调用r.run()
@Dog,我仍然会遇到同样的错误。你不能调用外部的run()
从另一个Runnable
——内部Runnable
不知道在哪里声明它。你到底想干什么?我不知道我能不能理解你。这如何解释为什么代码不能编译?