2012-05-10 15 views
0

次のコードでわかるように、私はActionListenerの匿名の内部クラスからJLabelにアクセスしています。これは私にエラーがないので、これはどのように許可されますか?JLabelがINSIDEの場合、メソッドは最終修飾子なしでは許可されていませんか?Java - 匿名の内部クラスから非最終変数にアクセスする方法を教えてください。

JLabel e = new JLabel(""); 
     public void myMethod() { 

      JButton b = new JButton("ok"); 
      b.addActionListener(new ActionListener() { 

       @Override 
       public void actionPerformed(ActionEvent arg0) { 
        e.setSize(200,200); 

       } 

      }); 

     } 
+1

[Java - 匿名の内部クラスからの変数へのアクセス](http://stackoverflow.com/questions/10524635/java-accessing-variables-from-an-anonymous-inner-class):両方の理由を尋ねるローカル変数ではない非最終フィールドにはアクセスできますか?それとも私は何かが恋しい?もし私がしたら - 明確にしてください。 – amit

答えて

3

変数はdefのメソッド内であれば、それはローカル変数だ - そして、あなたはそのメソッドの実行後に、それをそのローカル変数の寿命を存在するオブジェクトをインスタンス化しています、終了しました(メソッドの返り時に破棄されるメソッドのスタックフレームにあります)。これを行うにはをすべてコンパイラの魔法が必要です。これは通常、closureと呼ばれています。コンパイラは実際にActionListenerを実装するクラスを合成し、ローカル変数の値がコピーされるインスタンス変数を持ちます。

スレッドセーフであるため、finalのバールでのみ閉じることができるJava固有の制限です。ここでの話は、ローカルのvarは常にスレッドセーフであることはJava開発者の直感に浸っています。メソッドの実行の途中で変更することはできません(そのメソッドによって明示的に変更は行われません)。その上にデーターがないことなどがあります。クローズが現在実行中のメソッドと並行して実行され、そのvarを変更することができるように、非最終バルスを閉じることができれば、これは違反します。それはいくつかの非常に直観的ではない行動につながります。

は、しかし、(ややラメ)の回避策があります:

public void myMethod() { 
    final JLabel[] e = {new JLabel("")}; 
    JButton b = new JButton("ok"); 
    b.addActionListener(new ActionListener() { 
     @Override public void actionPerformed(ActionEvent arg0) { 
     e[0].setSize(200,200); 
    }}); 
} 

eは今、ヒープ上に常駐し、メソッドのスタックフレームで破壊されない1要素の配列、です。また、ではなく、スレッドセーフであり、そのリスナーはその値を全く異なる値に簡単に変更できることを直感的に理解することができます。ここに示されているメソッドは、その中に明示的な変異コード。

+0

*「スレッドセーフに関する懸念から、最終的なバールでのみ閉じることができるJava固有の制限です」* - 実際は、最終的なローカル変数アクセスではJVMがクロージャをサポートする必要があります。外部メソッドのローカル変数は、他のメソッド呼び出しが終了した後にも有効である必要があります。あなたはこれを引き起こすために複数のスレッドを必要としません... –

+0

しかし...彼ら** **は生きています。この例では、アクションが実行されるたびに 'e'を逆参照します。つまり、' myMethod'が返された過去の方法です。 –

関連する問題