簡體   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