PR

【Java】匿名クラスとは?1分でわかりやすく使いどころを解説

Java

匿名クラス(anonymous class)とは、その名の通り「クラス名を持たないクラス」のことです。Javaではクラスを作成するとき、多くの場合は下記のようにクラス名を定義してからコードを書きます。

public class MyClass {
    // クラス名: MyClass
}

一方、匿名クラスではクラス名を付けずに定義し、インスタンス化を同時に行います。主な特徴や使いどころ、メリットなどを段階的にご説明します。

public class Main {
    public static void main(String[] args) {
        Greeting g = new Greeting() {
            @Override
            public void sayHello() {
                System.out.println("こんにちは(匿名クラス)");
            }
        };
        g.sayHello();  // 出力: こんにちは(匿名クラス)
    }
}

interface Greeting {
    void sayHello();
}

✔ ポイント

  • Greeting というインターフェースをその場で実装
  • クラス名を付けずに new Greeting() { ... } で定義して即インスタンス化
  • 一度きりの使い捨てに便利!
スポンサーリンク

匿名クラスが生まれた背景

Javaはオブジェクト指向言語のため、実装を行うには基本的に「クラスを定義して、そのクラスのインスタンスを作る」という手順が必要になります。ですが、例えば1回だけ使うためだけに新しいクラスファイルを定義するような場面ではちょっと煩雑なので、それを便利にするために生まれたのが匿名クラス。

例えばGUIプログラミングやイベントリスナーを作る際、イベントハンドラ用に「インターフェースを実装するクラスを別に定義→インスタンス化」という手順を踏むことがよくあります。しかし「イベントを処理するためだけの短い実装をわざわざ別のクラスとして定義するほどでもない」という状況が多々発生します。そこで匿名クラスを使い、コード上で素早くインターフェースの実装(あるいはクラスの継承)を記述できるようになれば、クラスをファイルとしては増やす必要もなくなります。

ここでは、要するに「さくっと何らかの処理を定義したいな~」というときにつかえるのが匿名クラスだ!と理解できればまずはOKです。

Java:匿名クラスの書き方/構文ルール

匿名クラスの基本形は次のどちらかです。

パターン1 あるクラスを継承しつつ、そのメンバーをオーバーライドする

    new 親クラス() {
        // 必要であればメソッドをオーバーライド
    }
    

    パターン2 あるインターフェースを実装しつつ、そのメソッドを定義する

    new インターフェース() {
        // インターフェースの抽象メソッドを実装
    }
    

    ポイントは「new の直後にクラスやインターフェースを指定し、波括弧 {} の中にそのクラスやインターフェースのメソッド実装を書く」ことです。

    少し直感に反するかもしれません。けど、匿名クラスは 「クラス定義(中にメソッド定義)+インスタンス化」を一気にやってるイメージで覚えるとわかりやすいかも。

    💡これまでの流れ(ふつうのクラス)

    // クラス定義(メソッドもここで定義)
    class MyTask {
        void execute() {
            System.out.println("実行中");
        }
    }
    
    // インスタンス化
    MyTask task = new MyTask();
    task.execute();
    

    💡匿名クラスの場合

    Object task = new Object() {
        void execute() {
            System.out.println("匿名で実行中");
        }
    };
    

    クラス定義(+ メソッド定義)と同時に newしてるということ。

    やっていること通常クラス匿名クラス
    クラスを定義するclass ○○ {}new ○○() {}
    メソッドを定義するクラスの中{} の中
    インスタンスを作るnew ○○()new ○○() { メソッド定義 }

    「クラスを定義してからnew」じゃなくて、「newしながら定義してる」という逆転の発想です。

    サンプルコード1:クラスを継承するパターン

    public class Main {
        public static void main(String[] args) {
            Animal animal = new Animal() {
                @Override
                public void speak() {
                    System.out.println("にゃー");  // 例として猫っぽい鳴き声
                }
            };
            animal.speak();  // 「にゃー」
        }
    }
    
    class Animal {
        public void speak() {
            System.out.println("…");  // デフォルト実装
        }
    }
    

    ↑の例では、Animal というクラスを継承した「名前のないクラス」を new Animal() { ... } の部分で書き、そのインスタンスを animal に代入しています。通常であれば継承用に新しいクラス Cat extends Animal を定義する必要があるかもしれませんが、1回しか使わないのであれば匿名クラスで済ませてしまうこともできます。

    サンプルコード2:インターフェースを実装するパターン

    public class Main {
        public static void main(String[] args) {
            Runnable runner = new Runnable() {
                @Override
                public void run() {
                    System.out.println("匿名クラスでRunnableを実装");
                }
            };
            runner.run();  // 「匿名クラスでRunnableを実装」
        }
    }
    

    このように、あるインターフェース(例では Runnable)を実装して、そのメソッドをすぐ書いてしまう形です。new Runnable() { ... } の部分が匿名クラスの実体になります。

    なぜ匿名クラスを使うのか?メリットと注意点

    匿名クラスは「1回しか使わないクラスを、その場で簡潔に書ける」ことがうれしいクラスです。一応この章ではどんな嬉しさがあって、逆にどんな注意点があるのか?を整理しておきます。

    匿名クラスのメリット

    1. コードの凝縮
      新しいファイルを作らず、インターフェース実装やクラス継承のコードをその場でサッと書けるので、一度限りの実装に便利です。
    2. 可読性(ある程度)
      処理内容が短ければ、匿名クラスとしてまとめて書いてしまうことで「この箇所でしか使わない実装」であることが明確になります。別のクラスファイルを探す手間を省けるケースもあります。

    匿名クラスのデメリット・注意点

    1. コードが長くなりがち
      メソッドの数が多いインターフェースを匿名クラスで実装すると、1カ所に多くのメソッドがずらりと並ぶ可能性があります。読みづらい場合は素直に別クラスを作るほうが見通しが良いでしょう。
    2. 再利用ができない
      名前を持たず、その場でクラスを定義しているため、同じ匿名クラスを別の箇所で再利用することはできません。同じような実装が複数個所に存在する場合、むしろ共通化できるクラスとして普通に定義するほうが保守しやすいケースがあります。
    3. ラムダ式(Java 8以降)との違い
      Java 8以降はラムダ式を用いて、特に「関数型インターフェース」の実装を簡潔に書くことができます。たとえば RunnableComparator<T> のように抽象メソッドが1つしかないインターフェースなら、匿名クラスよりもラムダ式のほうがずっと短く書け、可読性も高くなることが多いです。
      ただし、匿名クラスはインターフェースだけでなく“クラスの継承”も行えるという点がラムダ式との大きな違いです。継承が必要な場合にはラムダ式だけでは対応できません。

    匿名クラスとラムダ式の使い分け

    Java 8以降は匿名クラスの出番が減ったと言われます。その理由としては、関数型インターフェース」を実装するだけであれば、ラムダ式のほうが短く書ける」 からです。

    // 匿名クラスでRunnableを実装
    Runnable r = new Runnable() {
        @Override
        public void run() {
            System.out.println("匿名クラス");
        }
    };
    

    これがラムダ式だとこうなります:

    Runnable r = () -> System.out.println("ラムダ式");
    
    // Runnable には run() しかないとJavaが分かっているので、ラムダ式では「メソッド名」も「@Override」も要りません✨

    ラムダ式は、もはやオーバーライドするメソッドが1個しかないことが自明だから、メソッド名も指定する必要がないよ!っていう書き方です。詳しくは以下の記事をご覧ください。

    一方、匿名クラスはクラスの継承を行える点や、複数のメソッドをオーバーライドする必要があるインターフェースや抽象クラスの場合など、ラムダ式では対応できないケースがあります。そのため「継承が必要な場面や抽象メソッドが複数あるインターフェースを実装する場合」「わずかに追加メンバーを持ちたい場合」などでは、依然として匿名クラスが選択肢となります。

    まとめ 匿名クラスとは?

    • 匿名クラスとは、クラス名を持たないままクラスを定義し、インスタンス化まで同時に行う仕組み。
    • メリット: 新たにクラスを用意せずに、その場で1回限りの処理を簡潔に実装できる。
    • デメリット: コードが長くなりやすい場合がある、再利用しにくい、抽象メソッドが多い場合に可読性が落ちる。
    • Java 8以降との関係: ラムダ式の登場で、関数型インターフェースの実装はラムダ式が主流。ただし、継承が必要な場合や複数メソッドの実装が必要なケースなどでは匿名クラスが有効。

    基本的には「一度きりの簡易実装」「GUIなどのイベントリスナー」などで使用することが多いです。Java 8以降はラムダ式の存在により、匿名クラスの使用頻度は減ったものの、クラスを継承する必要がある場面では今もなお必要な選択肢として活用され続けています。

    タイトルとURLをコピーしました