クラスのメンバとして、クラスを定義する — メンバクラス
まずは、先ほどのリスト1をよく見かけるようなクラス定義で書いてみましょう。
public class HelloListener implements View.OnClickListener { //(1) /** * 入力画面部品。 */ private EditText _input; /** * 出力画面部品。 */ private TextView _output; /** * コンストラクタ。 * 画面部品をあらかじめもらい、フィールドに保持しておかないと、onClick()メソッドで利用できない。 * * @param input 入力画面部品。 * @param output 出力画面部品。 */ public HelloListener(EditText input, TextView output) { _input = input; _output = output; } @Override public void onClick(View v) { String inputStr = _input.getText().toString(); _output.setText(inputStr + "さん、こんにちは!"); } }
public class MainActivity2 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); EditText input = (EditText) findViewById(R.id.etName); TextView output = (TextView) findViewById(R.id.tvOutput); Button button = (Button) findViewById(R.id.btClick); HelloListener listener = new HelloListener(input, output); // (2) button.setOnClickListener(listener); } }
通常、OnClickListenerのようなインターフェースを使うとき、それをimplementsしたクラスを作成し、それを実行クラスで使用します。
たとえば、(1)のようなリスナークラスを作成し、実行クラスの側では(2)のように、インスタンス化して使います。
しかし、ここで定義しているHelloListenerクラスは、MainActivity2クラスの中でしか利用しないクラスです。このようなクラスを、別々のクラスとして定義するのは管理上望ましくありません。そこで、以下のようにコードを書き換えます。
public class MainActivity3 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button = (Button) findViewById(R.id.btClick); HelloListener listener = new HelloListener(); button.setOnClickListener(listener); } /** * ボタンをクリックしたときのリスナークラス。 */ private class HelloListener implements View.OnClickListener { @Override public void onClick(View v) { EditText input = (EditText) findViewById(R.id.etName); TextView output = (TextView) findViewById(R.id.tvOutput); String inputStr = input.getText().toString(); output.setText(inputStr + "さん、こんにちは!"); } } }
このクラス内には、MainActivity3クラスのメンバとしてHelloListenerがあります。これは、classキーワードがあることからわかるように、MainActivity3クラス内で入れ子に定義されたクラスであり、ネスト(入れ子)クラスの一種です。あるいは、クラスのメンバであることから、より限定的にメンバクラスとも呼ばれます。
ではなぜ、このようなものが存在するのでしょうか。それは、クラス再利用の防止と管理のためです。
先ほども述べたように、HelloListenerクラスは、MainActivity3クラス以外では使いようがないクラスです。クラスを設計するうえで、あるクラスだけにしか使われないクラスを作る必要がでてくる場合があります。その際に、独立したクラスとして定義した場合、想定されずに他から利用される可能性が高くなり、それはすなわち、バグにつながります。また、別ファイルで作ることで、どのクラスとどのクラスが結びついているのかがわからなくなります。
これらを防止するためには、クラス内でクラスを作成した方がよく、そのためにネストクラス(メンバクラス)があるのです。
厳密に言えば、メンバクラスの場合は、フィールドやメソッドといった他のメンバ同様、public宣言にすることで、外部からも参照できます。しかし、それではわざわざメンバクラス化する意味がありません。そこで、private宣言にし、完全に隠蔽します。
今回のサンプルでは、HelloListenerクラスはprivate宣言にしてあります。