ボタンクリックリスナーがあり、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は私を最終にするように要求するのですか?
OnCreate()メソッドが戻ると、ローカル変数がスタックからクリーンアップされるため、ローカル変数は存在しなくなります。ただし、匿名クラスオブジェクトのnew View.OnClickListener()は、これらの変数を参照します。原因は間違った動作なので、Javaこれを許可しないでください。
最終的な後は定数になります。したがって、ヒープに格納され、匿名クラスで安全に使用できます。
匿名内部クラスは、ローカル変数のコピーを取得することにより、その囲んでいるスコープを参照します。匿名内部クラスのintの値を変更する場合は、ハックを行う必要があります。
final int[] arr = new int[1];
arr[0] = 10;
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
arr[0]++;
}
匿名の内部クラス内でアクセスしているためです。あなたはそれをすることはできません。最終的にしてからread匿名の内部クラスから取得できますが、インクリメントすることはできません。
オプション:
AtomicInteger
など他の場所からi
にアクセスする必要がない限り、おそらく2番目のオプションを優先します。正直に言うと、3番目のオプションは少し厄介なハックだと思います。
変数final
を作成する必要があります。これは、内部では、そのような匿名の内部クラスが単純に 構文糖衣構文 であり、ネストされたクラスoutsideにコンパイルされるためです。 )包含メソッドのスコープ。
これは、メソッド内で宣言された変数のいずれも内部クラスにアクセスできないことを意味します。そのため、コンパイラーは別のトリックをプルします-そしてコピーの値クラスの非表示コンストラクター。メソッド内の変数への変更に一致するようにこのコピーが更新されないプログラマーの混乱を避けるために、そのような変更がないことを確認するのは最終的なものでなければなりません。
ここでの目標はインクリメントする整数を使用することであり、参照のみが最終である必要があるため(オブジェクト自体は不変である必要はありません)、final AtomicInteger i
を宣言し、コールバックから必要に応じてインクリメントできます。
i
変数をインクリメントする必要があるため、最終的にすることはできません。代わりに、クラスメンバーにすることができます。