無名クラスを作成したスコープのローカル変数を無名クラスに渡す
半年振りに書いたブログ記事が「MacBook Air 11インチ欲しい!」だけじゃ寂しいので、最近気付いたJavaプログラミングのネタについてでも書きます。Javaで「無名クラスを生成したメソッド内、同一スコープのローカル変数を渡す方法」です。
便利ですね無名クラス。クラス名を考えなくてもいいし、それらクラス数の管理が減ってコードも見やすくなる?(メソッド内局所に限っては複雑になりますが)気がします。
最近だとAndroid開発なんかも流行ってますが、アレもイベント処理が多くて無名クラスを使用する場面も多々あると思います。
そんな無名クラスですが「コンストラクタ(名前が無いので)」が定義出来ないなど、制限事項も多かったりします。そのひとつが表題の件になるのですが、具体的な例(Android)を挙げると、以下のようなコードが考えられます。
class Hoge{ public void fuga() { View view; int i = xxx; view.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { // ここでiの値を参照したいがどうしたらいいか } }); : : } }
無名クラスで実装しているonClickでiを参照したいのですが、iはローカル変数なのでそのままでは参照できません。
まあメンバ変数にすれば参照可能なんですけど、↓の様に実装するのもHogeクラス自体に(クラス全体像として)不要なメンバが増えてしまうのであまり良い解決策では無いのかなと思います。
class Hoge{ private int i; public void fuga() { View view; int local_i = xxx; this.i = local_i; view.setOnClickListener(new View.OnClickListener(){ public void onClick(View v) { // これならiを参照できる } }.setIntager(i)); : : } }
その場合、↓のように実装すればHogeクラスのメンバを増やしたりせず、ローカル変数を渡せる事に気付きました。
class Hoge{ public void fuga() { View view; int i = xxx; view.setOnClickListener(new View.OnClickListener(){ private int i; public View.OnClickListener setIntager(Int i) { this.i = i; return this; } public void onClick(View v) { // iは参照できる、大丈夫だ問題ない } }.setIntager(i)); : : } }
無名クラスはインタフェースのメソッドを定義するしか出来ないものと思ってましたが、独自メソッドやメンバも実装可能なんですね。
勿論、最終的にsetOnClickListenerへ無名クラスのインスタンスを渡す必要があるので、thisをreturnしちゃってるので、厳密にはSetterとは違うのかもしれませんけど。#こういう方法を使う場合どんなメソッド名が適切なんでしょう。
Java系言語を知ってる人からすれば「当たり前ジャン」的な事なのかもしれないけど、「こういう方法もあるのか」と気付かされた事でした。