![](/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.