Javaの匿名クラス

1. 前書き

このチュートリアルでは、Javaの匿名クラスを検討します。
それらのインスタンスを宣言および作成する方法について説明します。 また、それらのプロパティと制限についても簡単に説明します。

2. 匿名クラス宣言

*匿名クラスは名前のない内部クラスです*。名前がないため、匿名クラスのインスタンスを作成するために使用することはできません。 その結果、使用時に匿名クラスを単一の式で宣言およびインスタンス化する必要があります。
既存のクラスを拡張するか、インターフェースを実装します。

2.1. クラスを拡張する

存在するクラスから匿名クラスをインスタンス化するとき、次の構文を使用します。
link:/uploads/AnonymousClass-InstantiateFromClass-100x20.png%20100w []
括弧内に、拡張するクラスのコンストラクターに必要なパラメーターを指定します。
new Book("Design Patterns") {
    @Override
    public String description() {
        return "Famous GoF book.";
    }
}
当然、親クラスのコンストラクターが引数を受け入れない場合は、括弧を空のままにしておく必要があります。

2.2. インターフェイスを実装する

インターフェースから匿名クラスをインスタンス化することもできます:
link:/uploads/AnonymousClass-InstantiateFromInterface-100x18.png%20100w []
明らかに、Javaのインターフェースにはコンストラクターがないため、括弧は常に空のままです。 これは、インターフェイスのメソッドを実装するために行う唯一の方法です。
new Runnable() {
    @Override
    public void run() {
        ...
    }
}
匿名クラスをインスタンス化したら、後でそのインスタンスを参照できるように、そのインスタンスを変数に割り当てることができます。
Java式の標準構文を使用してこれを行うことができます。
Runnable action = new Runnable() {
    @Override
    public void run() {
        ...
    }
};
すでに述べたように、*匿名クラス宣言は式であるため、ステートメントの一部である必要があります*。 これが、ステートメントの最後にセミコロンを入れた理由を説明しています。
明らかに、インスタンスをインラインで作成すると、インスタンスを変数に割り当てることを回避できます。
List<Runnable> actions = new ArrayList<Runnable>();
actions.add(new Runnable() {
    @Override
    public void run() {
        ...
    }
});
特に_run()_メソッドの実装に多くのスペースが必要な場合は、コードの可読性が低下する可能性があるため、この構文は細心の注意を払って使用する必要があります。

3. 匿名クラスのプロパティ

通常のトップレベルのクラスに関して匿名クラスを使用する場合、特定の特殊性があります。 ここでは、最も実用的な問題について簡単に触れます。 最も正確で更新された情報については、https://docs.oracle.com/javase/specs/jls/se8/html/index.html [Java言語仕様]を常に参照してください。

3.1. コンストラクタ

無名クラスの構文では、複数のインターフェイスを実装することはできません。 構築中に、*匿名クラスのインスタンスが1つだけ存在する可能性があります*。 したがって、それらは決して抽象的ではありません。 名前がないため、拡張することはできません。 同じ理由で、匿名クラスは明示的に宣言されたコンストラクタを持つことはできません。
実際、コンストラクターが存在しないことは、次の理由により問題を表していません。
  1. 宣言すると同時に匿名クラスインスタンスを作成します
    them

  2. 匿名クラスインスタンスから、ローカル変数にアクセスできます。
    クラスのメンバーを囲む

3.2. 静的メンバー

匿名クラスには、定数であるものを除き、静的メンバーを含めることはできません。
たとえば、これはコンパイルされません:
new Runnable() {
    static final int x = 0;
    static int y = 0; // compilation error!

    @Override
    public void run() {...}
};
代わりに、次のエラーが表示されます。
The field y cannot be declared static in a non-static inner type, unless initialized with a constant expression

3.3. 変数の範囲

匿名クラスは、クラスを宣言したブロックのスコープ内にあるローカル変数をキャプチャします。
int count = 1;
Runnable action = new Runnable() {
    @Override
    public void run() {
        System.out.println("Runnable with captured variables: " + count);
    }
};
ご覧のとおり、ローカル変数_count_と_action_は同じブロックで定義されています。 このため、クラス宣言内から_count_にアクセスできます。
*ローカル変数を使用できるようにするには、それらが実質的に最終でなければならないことに注意してください。* JDK 8以降、キーワード_final_を使用して変数を宣言する必要はなくなりました。 それでも、これらの変数は_final_でなければなりません。 そうしないと、コンパイルエラーが発生します。
[ERROR] local variables referenced from an inner class must be final or effectively final
コンパイラが変数が実際に不変であるとコード内で判断するためには、変数に値を割り当てる場所が1つだけ存在する必要があります。 効果的な最終変数の詳細については、次の記事を参照してください。https://www.baeldung.com/java-lambda-effectively-final-local-variables最終?]â€
すべての内部クラスとして、*匿名クラスはそれを含むクラスのすべてのメンバーにアクセスできます*。

4. 匿名クラスの使用例

匿名クラスのアプリケーションは非常に多様です。 いくつかの可能なユースケースを調べてみましょう。

4.1. クラス階層とカプセル化

アプリケーションのクラスの階層をよりきれいにするために、一般的な使用例では内部クラスを使用し、非常に特殊な使用例では匿名クラスを使用する必要があります。 内部クラスを使用する場合、包含クラスのデータのより細かいカプセル化を実現できます。 最上位クラスで内部クラスの機能を定義する場合、外側のクラスはそのメンバーの一部の_public_または_package_可視性を持つ必要があります。 当然、あまり高く評価されていない、または受け入れられていない状況もあります。

4.2. よりクリーンなプロジェクト構造

いくつかのクラスのメソッドの実装を即座に変更する必要がある場合、通常、匿名クラスを使用します。 この場合、最上位クラスを定義するために、プロジェクトに新しい_ *。java_ファイルを追加することを避けることができます。 これは、そのトップレベルクラスが1回だけ使用される場合に特に当てはまります。

4.3. UIイベントリスナー

グラフィカルインターフェイスを備えたアプリケーションでの匿名クラスの最も一般的な使用例は、さまざまなイベントリスナーを作成することです。 たとえば、次のスニペットでは:
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        ...
    }
}
インターフェイス_ActionListener._を実装する匿名クラスのインスタンスを作成します。ユーザーがボタンをクリックすると、そのmethod_actionPerformed_メソッドがトリガーされます。
link:/java-streams[SinceのJava 8、ラムダ式]はいえ、より好ましい方法であるように見えます。

5. 一般的な写真

上記で検討した匿名クラスは、https://www.baeldung.com/java-nested-classes [nested classes]の特定のケースにすぎません。 一般的に、* classネストされたクラスは* *別のクラスまたはインターフェース内で宣言されたクラス*:
link:/uploads/nested-classes-100x44.png%20100w []
図を見ると、匿名クラスと_local_および_nonstaticメンバーのones_がいわゆる_inner classes_を形成していることがわかります。 _staticメンバー_クラスと一緒に、ネストされたクラスを形成します。

6. 結論

この記事では、Java匿名クラスのさまざまな側面を検討しました。 ネストされたクラスの一般的な階層についても説明しました。
いつものように、完全なコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-lang-oop-2[GitHubリポジトリ]から入手できます。