匿名クラスについてのまとめ

匿名クラス (Anonymous Inner Classes) 概要

  • Java 7以降
  • クラスの定義とインスタンス化を同時に行う仕組み
  • 使用方法として以下の2つがある
      1. クラスの拡張
      2. インターフェースの実装
    

1. クラスの拡張

匿名クラスによって、インスタンス化時に拡張を実装することができる

構文

new クラス名() {
        // 変数の定義
        private int variable = 5;
        // オーバーライド
        @Override toString() {
                ...
        }
}
  • インスタンスの生成と { ... } ブロック内部でクラスの拡張を定義している

例1. Threadインスタンスの生成とrunメソッドのオーバーライド

ThreadメソッドはRunnableをimplementsしているので、生成時に匿名クラスを使ってOverrideする事ができる

public static void main(String[] args) {
        // Threadインスタンスの生成と
        Thread t = new Thread() {
                @Override
                public void run() {
                        System.out.println("Child Thread");
                }
        }
        t.start();
}

例2. Comparableをimplementsしているオブジェクトのソート操作を変更する

デフォルトでは rollNo によってソートされる Studentクラスを実行時に名前順にソートするように変更させます。

Studentクラス

Comparableを実装しています。

static class Student implements Comparable<Student> {
        int rollno;
        String name;

        Student(int rollno, String name) {
                this.rollno = rollno;
                this.name = name;
        }

        // rollno順にソートされる
        public int compareTo(Student other) {
                return Integer.compare(this.rollno, other.rollno);
        }

        @Override
        public String toString() {
                return "rollno: " + this.rollno + " name: " + this.name;
        }
}

匿名クラスによるStudentの拡張

匿名クラスを使ってクラスの拡張とインスタンスの生成を同時に行っています。

public static Student createStudent(int rollno, String name) {
        return new Student(rollno, name) {
                @Override 
                public int compareTo(Student other) {
                        // 名前順に変更
                        return this.name.compareTo(other.name);
                }
        };
}

実行結果

public static void main(String[] args) { 
        var sato = createStudent(1, "sato");
        var tanaka = createStudent(2, "tanaka");
        var ando = createStudent(3, "ando");
        var maeda = createStudent(4, "maeda");

        var students = new Student[]{tanaka, sato, maeda, ando};
        Arrays.sort(students);
        System.out.println(Arrays.toString(students));
        
        // 実行結果
        // [rollno: 3 name: ando, rollno: 4 name: maeda, rollno: 1 name: sato, rollno: 2 name: tanaka]

}

Comparable vs Comparator

Comparableは、クラスが自然な順番を持っていることを示すインターフェースです。 したがって実行時にクラスが持つ自然な並びとは異なる順番にソートさせる場合は、Comparable ではなく java.util.Comparator を使ったほうが適切です。

2. インターフェースの実装

インターフェースに必要となるメソッドの実装を行い、そのままインスタンス化することができる。

構文

new インターフェース名() {
        // インターフェースに必要となるメソッドを実装
}

1. Runnableの実装とインスタンス

public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
                public void run() {
                        System.out.println("Child Thread");
                }
        }
        t.start();
}

2. ActionListenerの実装とインスタンス

JButton button = new JButton("Click Me!");
button.addActionListener(new ActionListener() {
        // 変数も定義できる
        private int iClickCount = 0;

        public void actionPerformed(ActionEvent e) {
                ((JButton)e.getSource()).setText(String.format("%d times Clicked", ++iClickCount));
        }
});

匿名クラスの特徴

  • コンストラクタが存在しない
  • として評価される
      * 変数や関数の引数、返り値にわたすことができる
    

ラムダ式との関係

  • 匿名クラスはJava 7で実装された
  • ラムダ式Java 8で実装された@FunctionalInterfaceに特化した匿名クラスの発展形

参照

Anonymous Inner Class in Java - GeeksforGeeks

匿名クラス(無名クラス)とイベントリスナー - 愚鈍人