Javaの匿名内部クラスを比較する


javaの匿名内部クラスについて、いい比較があったのでご紹介します。
引用先は、金田浩明『超初心者でも大丈夫 はじめてのAndroidプログラミング 改訂版』です。

匿名内部クラスとは

匿名内部クラス(anonymous inner class:無名インナークラスとも)とは、
クラスの名前を決めずに(匿名)、外部から参照できない形で(内部)定義するクラスのことです。
上記参考書では「無名インナークラス」と紹介されていますが、
下記のサイトを見ると、一応クラスに名前はあるらしいので、ここでは「匿名」の方を採用しました。
最も、この「匿名されているクラス名」を使えば外部からクラスを使用することもできるので
(そこで宣言されたインスタンスは参照できないが)
内部/インナーを除いた「匿名クラス」「無名クラス」という言い方もあります。
irof.hateblo.jp

C言語の無名○○

ちなみに、似たようなものがC言語にもあります。
「無名構造体」「無名共用体」「無名列挙型」などがそれです。
(こちらは「匿名〜」よりも「無名〜」の方がメジャーですかね?)
それぞれの型の定義を、その型の変数の定義と同時に行ってしまうものです。

/* 無名構造体 */
struct{
    int a;
    int b;
} anonymous_struct;

/* 無名共用体 */
union{
    int k;
    int l;
} anonymous_union;

/* 無名列挙型 */
enum{
    int x,
    int y,
} anonymous_enum;

型の名前がないので、関数の引数などに使うことはできません。
ですので、余り使いどころがないという話もあるのですが、
私は、特にC言語にはクラスという概念がないので、
データをひとかたまりにしたい時に無名構造体を使ったり、
組み込みC言語で、複数の形式で変数の読み書きをしたい時に無名共用体を使ったり、
配列を連想配列的に使いたい時(なので型はいらない)に無名列挙型を使ったりします。

匿名内部クラスを使った場合と使わなかった場合

さて、本題に戻ります。
引用先では、JavaによるAndroidアプリ開発において、
OnClickListenerを設定するシーンを例に、匿名内部クラスを使用した場合と
使用しない場合とを紹介しています。

匿名内部クラス使用例
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button tapHere = (Button)findViewById(R.id.tapHere);
    tapHere.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View v){
            TextView textView = (TextView)findViewById(R.id.textView);
            textView.setText("ボタンがタップされました");
        }
    });
}
//金田, 2017, pp58-59.
匿名内部クラス非使用例
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Button tapHere = (Button)findViewById(R.id.tapHere);
    MyOnClickListener myOnClickListener = new MyOnClickListener();
    tapHere.setOnClickListener(myOnClickListener);
}

public class MyOnClickListener implements View.OnClickListener{
    @Override
    public void onClick(View v){
        TextView textView = (TextView)findViewById(R.id.textView);
        textView.setText(R.string.hello_world);
    }
}
//金田, 2017, pp60-61.

上記2例について、
相違部を赤枠、赤枠内の一致部を緑枠及び青枠で示したのが下の図です。
(純粋に使用例と非使用例を比較するため、非使用例の方は若干内容を変えています)

これを見ると、for文の条件式の中でイテレータを宣言・定義するC++Javaの構文を彷彿とさせます。

for(int i=0;i<num;i++){
    //繰り返し処理
}

このint iと同じように、
関数の引数の中で、新しいクラスを定義しているのが匿名内部クラスと考えると
わかりやすいと思います。
他ではそう目にしない

});

の括弧の並びも、これで納得でしょう。