2015-01-17 23 views
2

有沒有辦法來克服在匿名內部類中訪問的變量必須是最終的事實?克服匿名類中的最終變量

例如我有一個按鈕,應該隨時報告列表的大小。在while循環以後的list應該得到修改,並在每個週期list將新實例化的,如果list是最終

// has to be final 
final ArrayList<String> list = new ArrayList<String>(); 

MyButton button = new MyButton() { 
    @Override 
    public int getValue() { 
     return list.size(); 
    } 
}; 

while (true) { 
    // modify/re-assign list 
} 

做到這一點的方法是使list一個靜態變量,這是不可能的,但那不是最佳。有沒有另一種方法可以克服這一點?

+0

該列表不一定是靜態變量。它只需要是按鈕有權訪問的對象的可變字段。 –

+1

你真的需要重新分配嗎?或者你可以清除它並更新它嗎? – khelwood

+0

@ khelwood不,不是真的。我只是假設創建一個新實例會更快。 – TomTom

回答

3

不,沒有。

這不是一件可以克服的事情。由於訪問字段變量的匿名類是閉包,所以字段變量的範圍延伸超過原始聲明的生命週期。

Java實現此方法的方式是在匿名類中創建引用的本地副本。你可以認爲這這等同於:

final ArrayList<String> list = new ArrayList<String>(); 

class MyButtonImpl extends MyButton { 
    final ArrayList<String> list; 

    public MyButtonImpl(final ArrayList<String> list) { 
     this.list = list; 
    } 

} 

MyButton button = new MyButtonImpl(list); 

所以你可以看到,在MyButtonImpl提及list不同參考。在方法中重新分配參考不會影響MyButtonImpl中的參考。

由於這個原因,Java不允許在匿名類中引用非(有效)final字段 - 它不會像預期的那樣工作。

至於對付你的具體問題,或者:

  • 不重新分配list,只需使用clear();或
  • 創建一個本地class,如我所做的一樣,並使用其引用;或
  • 使用一個可變的容器,諸如AtomicReference

最後建議是骯髒的黑客,但可以在一些有用的,稀有的,箱子。

1

解決此問題的一種方法是將列表作爲父類的實例變量。這樣,您將始終可以訪問匿名類中的變量,並且也應該可以初始化它。

由於它是一個內部類,它將有權訪問父類的實例變量。

public class Parent{ 

     ArrayList<String> list = new ArrayList<String>(); 

     // this inner class will work alongside the parent class 
     // hence its possible to share the instance properties of Parent 
     // with the Child. 

     MyButton button = new MyButton() { 
      @Override 
      public int getValue() { 
      return list.size(); 
      } 
     }; 

    }