無名クラスとは、名前の無いクラスのことです。既存のクラスを少しだけ修正したクラスを作りたい場合で敢えて名前をつけるほどでもない場合や、インターフェイスを実装したクラスを作りたい場合で、敢えて名前をつけるほどでもない場合に使用されます。
内部クラスのときと同様に、親クラスの privateなメソッドやフィールドにアクセスすることができます。
本節では以下の 2つについて、それぞれ解説していきたいと思います。
無名クラスは、インスタンスを作成したあとに { } を記述することで作成します。まずは、最もシンプルな例を挙げます。
ソースコードは以下の通り。
Y301/Y301.java
(13行目に黄線が生じますが問題ありません)
import java.awt.Point; /** * 無名クラスを利用します。 */ public class Y301 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { // Point型インスタンスを生成する Point point1 = new Point(10, 20); // Point型を継承した無名クラスのインスタンスを生成する Point point2 = new Point(15, 25) {}; System.out.println("変数 point1の参照先インスタンスの内容は " + point1); System.out.println("変数 point2の参照先インスタンスの内容は " + point2); } }
実行結果の例は以下の通り。
変数 point1の参照先インスタンスの内容は java.awt.Point[x=10,y=20] 変数 point2の参照先インスタンスの内容は Y301$1[x=15,y=25]
14行目では Point型インスタンスを 1個生成しています。そして、16行目では Pointクラスを継承した無名クラスのインスタンスを 1個生成しています。今回はメソッドをオーバーライドしていません。これが最もシンプルな無名クラスの例ということになります。
なお、「Y301$1」は、Y301が持つ 1番目の無名クラスという意味です。
続いて、メソッドをオーバーライドする無名クラスの例を挙げます。
ソースコードは以下の通り。
Y302/Y302.java
import java.awt.Point; /** * 無名クラスを利用します。 */ public class Y302 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { // Point型インスタンスを生成する Point point1 = new Point(10, 20); // Point型を継承した無名クラスのインスタンスを生成する Point point2 = new Point(15, 25) { /** * デフォルトシリアルバージョンID(warning回避)。 */ private static final long serialVersionUID = 1L; @Override public String toString() { return "Point(" + this.x + "," + this.y + ")"; } }; System.out.println("変数 point1の参照先インスタンスの内容は " + point1); System.out.println("変数 point2の参照先インスタンスの内容は " + point2); } }
実行結果の例は以下の通り。
変数 point1の参照先インスタンスの内容は java.awt.Point[x=10,y=20] 変数 point2の参照先インスタンスの内容は Point(15,25)
無名クラスの宣言で、Pointクラスのメソッドをオーバーライドしています。無名クラスは、その性質上、独自のメソッドを宣言してもほとんど意味を持たないので、ほとんどの場合、既存のメソッドをオーバーライドすることになります。toStringメソッドをオーバーライドしたことで、実行結果が変わっています。
普段、予約語 newはクラス名とともに使用することがほとんどですが、無名クラスの場合には特別にインターフェイス名を指定することができます。
このような、インターフェイスを実装する無名クラスの場合には、インターフェイスで宣言されている抽象メソッドをすべて実装する必要があります。
なお、インターフェイスを実装した無名クラスの場合、スーパークラスは Objectクラスになります。
ソースコードは以下の通り。
Y303/Y303.java
/** * インターフェイスを実装した無名クラスを利用します。 */ public class Y303 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { ; // 何もしない } }; System.out.println("変数 runnableの参照先インスタンスの内容は " + runnable); } }
実行結果の例は以下の通り。
変数 runnableの参照先インスタンスの内容は Y303$1@413f9276
このプログラムには特段、スレッドを作るなどの意味はありません。
S203プロジェクトのリスナを無名クラスを使用して実現してみることにします。
ソースコードは以下の通り。
Y304/MyJFrame.java
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; /** * JFrameを継承したクラスです。 */ public class MyJFrame extends JFrame { /** * デフォルトのシリアルバージョン ID(warning回避)。 */ private static final long serialVersionUID = 1L; /** * ボタン1。 */ private JButton jButton1 = new JButton("朝"); /** * ボタン2。 */ private JButton jButton2 = new JButton("夜"); /** * ラベル1。 */ private JLabel jLabel1 = new JLabel("メッセージ欄"); /** * コンストラクタ。 */ public MyJFrame() { // レイアウトを設定する this.getContentPane().setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS)); // フレームにボタンとラベルを登録する this.getContentPane().add(this.jButton1); this.getContentPane().add(this.jButton2); this.getContentPane().add(this.jLabel1); // リスナを設定する this.jButton1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MyJFrame.this.jLabel1.setText("おはようございます"); } }); this.jButton2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MyJFrame.this.jLabel1.setText("こんばんは"); } }); } }
Y304/Y304.java
import javax.swing.JFrame; /** * リスナを利用します。 */ public class Y304 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { JFrame jFrame = new MyJFrame(); jFrame.setTitle("swing test"); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setSize(400, 300); // ウインドウを表示する(新しいスレッドが生成される) jFrame.setVisible(true); } }
実行結果は以下の通り。