匿名クラスではなぜ final 変数のみにアクセスできるのでしょうか? 質問する

匿名クラスではなぜ final 変数のみにアクセスできるのでしょうか? 質問する
  1. aaここでは final にしかできません。なぜですか? メソッド内でonClick()プライベート メンバーとして保持せずに再割り当てするにはどうすればよいですか?

    private void f(Button b, final int a){
        b.addClickHandler(new ClickHandler() {
    
            @Override
            public void onClick(ClickEvent event) {
                int b = a*5;
    
            }
        });
    }
    
  2. クリックしたときに戻すにはどうしたらいいでしょうか5 * a

    private void f(Button b, final int a){
        b.addClickHandler(new ClickHandler() {
    
            @Override
            public void onClick(ClickEvent event) {
                 int b = a*5;
                 return b; // but return type is void 
            }
        });
    }
    

ベストアンサー1

finalコメントで指摘されているように、Java 8 では暗黙的に使用できるため、この一部は無関係になります。ただし、匿名内部クラスまたはラムダ式では、実質的にfinal な変数のみを使用できます。


これは基本的にJavaの管理方法によるものです閉鎖

匿名内部クラスのインスタンスを作成すると、そのクラス内で使用されるすべての変数の値が、自動生成されたコンストラクターを介してコピーされます。これにより、たとえば C# コンパイラのように、コンパイラが「ローカル変数」の論理状態を保持するためにさまざまな追加型を自動生成する必要がなくなります... (C# が匿名関数で変数をキャプチャする場合、実際に変数をキャプチャします。つまり、クロージャはメソッドの本体から見える方法で変数を更新でき、その逆も同様です。)

値は匿名内部クラスのインスタンスにコピーされているため、メソッドの残りの部分で変数を変更できると奇妙に見えます。古い変数で動作しているように見えるコードが存在する可能性があります (実際には、別の時間に取得されたコピーで動作しているため、それが事実上発生することになります)。同様に、匿名内部クラス内で変更を加えることができる場合、開発者はそれらの変更が囲んでいるメソッドの本体内で表示されることを期待するかもしれません。

変数を final にすると、これらの可能性がすべてなくなります。値はまったく変更できないため、このような変更が可視かどうか心配する必要はありません。メソッドと匿名内部クラスが互いの変更を確認できるようにする唯一の方法は、なんらかの可変型を使用することです。これは、囲んでいるクラス自体、配列、可変ラッパー型など、何でもかまいません。基本的に、これは 1 つのメソッドと別のメソッド間の通信に少し似ています。つまり、 1 つのメソッドのパラメーターに加えられた変更は、その呼び出し元には表示されませんが、パラメーターによって参照されるオブジェクトに加えられた変更は表示されます。

JavaとC#のクロージャのより詳細な比較に興味があるなら、記事さらに詳しく説明します。この回答では Java 側に焦点を当てたいと思います :)

おすすめ記事