14

ボタンクリックリスナーがあり、onCreate()メソッドには次のようなローカル変数があります

 onCreate() {

 super.onCreate();

 int i = 10;

 Button button = (Button)findViewById(R.id.button);

 button.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            i++;
        }   
    });

Javaが私を最終的にするように要求するのはなぜですか?

4

5 に答える 5

29

onCreate() メソッドが戻ると、ローカル変数はスタックからクリーンアップされるため、存在しなくなります。ただし、匿名クラス オブジェクト new View.OnClickListener() はこれらの変数を参照します。原因は間違った動作であるため、Java ではこれを行うことができません。

final の後は定数になります。したがって、ヒープに格納され、匿名クラスで安全に使用できます。

于 2011-10-21T08:58:29.750 に答える
13

匿名内部クラスは、ローカル変数のコピーを取得することにより、その包含スコープを参照します。匿名内部クラスのintの値を変更する場合は、ハッカーを実行する必要があります。

final int[] arr = new int[1];
arr[0] = 10;
Button button = (Button)findViewById(R.id.button);

button.setOnClickListener(new View.OnClickListener() {
  arr[0]++;
}
于 2011-10-21T07:56:40.443 に答える
12

匿名の内部クラス内でアクセスしているためです。あなたはそれをすることはできません。それをfinalにして、匿名の内部クラスから読み取ることはできますが、それをインクリメントすることはできません。

オプション:

  • 代わりに、外部クラスのインスタンス変数にします
  • 代わりに、匿名内部クラスのインスタンス変数にします
  • ラッパーを使用します-たとえば、単一要素の配列、AtomicIntegerまたはそのようなもの

他の場所からアクセスする必要がない限り、おそらく2番目のオプションを優先しiます。正直なところ、3番目のオプションは少し厄介なハックだと思います。

于 2011-10-21T07:57:48.283 に答える
5

final内部的には、そのような匿名の内部クラスは、包含メソッドのスコープのネストされたクラスにコンパイルされる単なる構文糖衣であるため、変数を作成する必要があります。

これは、メソッド内で宣言された変数のいずれも内部クラスにアクセスできないことを意味します。そのため、コンパイラーは別のトリックをプルし、クラスの非表示のコンストラクターに値をコピーします。メソッド内の変数への変更に一致するようにこのコピーが更新されないプログラマーの混乱を避けるために、そのような変更がないことを確認するのは最終的なものでなければなりません。

ここでの目標は増分整数を使用することであり、参照のみが最終である必要があるため(オブジェクト自体は不変である必要はありません)、afinal AtomicInteger iを宣言して、コールバックから必要に応じて増分できます。

于 2011-10-21T07:57:56.767 に答える
4

変数をインクリメントする必要があるiため、最終的にすることはできません。代わりにクラスメンバーにすることもできます。

于 2011-10-21T08:00:27.837 に答える