Javaには匿名クラス(無名クラス)というのが存在する。今回はその存在意義と使い方を学ぼう。
作成
いつものように一緒に手を動かしながら学習していこう。決して見るだけで終えないこと。
PCApp.javaの作成
USB端子のついたパソコンをテーマに扱っていこう。ファイル1枚で行いたいのでまずは以下のようなメインメソッドのあるPCAppクラスを作成する。
public class PCApp {
public static void main(String[] args) {
}
}
IUsbインターフェイスの作成
USB接続ができることを表すIUsbインターフェイスを下に作成しよう。
USB接続したさいに何ができるかを記述する抽象メソッドexecute()のみを持つ
ここでつけたIUsbのIはInterfaceを表すIでInterfaceに名前をつける方法の一つ。
public class PCApp {
public static void main(String[] args) {
}
}
interface IUsb{
void execute();
}
PCクラスの作成
USB接続端子を持つPCクラスを作成しよう。今回はメソッドの引数にIUsb型のインスタンスが入ってくるものとする。何が接続されるかはわからないが、接続後はメモリーだったり、扇風機だったり、それぞれが動作することをイメージしている。(本物のパソコンも同じだ)
public class PCApp {
public static void main(String[] args) {
}
}
interface IUsb{
void execute();
}
class PC{
void executeUSB(IUsb usb){
usb.execute();
}
}
名前があるクラスを作る
それではまずは今までのように名前のあるクラスを作成する。USBメモリークラスを作成しよう。
public class PCApp {
public static void main(String[] args) {
}
}
interface IUsb{
void execute();
}
class PC{
void executeUSB(IUsb usb){
usb.execute();
}
}
class UsbMemory implements IUsb{
@Override
public void execute(){
System.out.println("メモリに書き込みます");
}
}
実行
それでは実際にUSBメモリーをパソコンにつないで実行してみよう。
public class PCApp{
public static void main(String[] args) {
PC pc=new PC();//PCインスタンスを作成
UsbMemory usbMemory=new UsbMemory();//USBメモリーを作成
pc.executeUSB(usbMemory);//->メモリに書き込みます
}
}
interface IUsb{
void execute();
}
class PC{
void executeUSB(IUsb usb){
usb.execute();
}
}
class UsbMemory implements IUsb{
@Override
public void execute(){
System.out.println("メモリに書き込みます");
}
}
ここまではよろしいだろうか?このようにインターフェイスを用いてクラス設計をしておくと、今後USB接続を持つどんな機器が発明されても接続して使うことができるのであった。
直接new
先程のコードはUsbMemoryインスタンス生成の際、1行使って作成したが。
UsbMemory usbMemory=new UsbMemory();//USBメモリーを作成
これは以下のように引数内でnewしても同じだ。
public static void main(String[] args) {
PC pc=new PC();//PCインスタンスを作成
pc.executeUSB(new UsbMemory());//->メモリに書き込みます
}
匿名クラス
それではいよいよ匿名クラスを作成してみよう。今回はUSBに接続する扇風機を匿名クラスで作成してみる。以下の1行を追記してみよう。
pc.executeUSB(new IUsb(){});
public static void main(String[] args) {
PC pc=new PC();//PCインスタンスを作成
pc.executeUSB(new UsbMemory());//->メモリに書き込みます
pc.executeUSB(new IUsb(){});
}
この奇妙な記述でIUsbインターフェイスを実装した名前のないクラスのインスタンス生成となる。
new インターフェイス名(){}
new インターフェイス名 丸括弧 波括弧と覚えてもらいたい
これはインターフェイスに限定するわけでなく、インターフェイスの部分にスーパークラスがきても、そのクラスを継承した名前のないクラスを作成することができる
new スーパークラス名(){}
抽象メソッドの実装
ここまで書いた段階でエクリプスなどの統合環境を使っている人は赤線で激しく怒られているはずだ。それもそのはず、名前があろうとなかろうとインターフェイスを実装したクラスは抽象メソッドをオーバーロードしなければならない。
波括弧のなかに記述
この匿名クラスの実装は波括弧の中に書く。以下のように抽象メソッドをオーバーライドしよう。
public static void main(String[] args) {
PC pc=new PC();//PCインスタンスを作成
pc.executeUSB(new UsbMemory());//->メモリに書き込みます
pc.executeUSB(new IUsb(){
@Override
public void execute(){
System.out.println("扇風機を回します");
}
});
}
}
実行
実行してみよう。
メモリに書き込みます 扇風機を回します
と出力されたはずだ。名前がある通常のクラスを作ることなしに扇風機機能を持つUSB機器を生成することができた。
このように実際にクラスを生成する手間を省いて、同じような効果が得られるのが匿名クラスのメリットだ。
Listの初期化
この匿名クラスの仕組みは様々なところで活用されている。よく見るのが以下のような実装。
List<Integer> list=new ArrayList<>(){
{
add(10);
add(20);
add(30);
}
};
System.out.println(list.get(0));//10
これはArrayListクラスを継承した名前のないクラスのインスタンスを生成して、インスタンスイニシャライザを使ってリストに初期値を入れている。
その先に待っているもの
いかがだっただろうか?匿名クラスの作り方や利用方法がなんとなく理解できたであろうか?実はこの話には続きがある。USBカードリーダーを作成したくなった場合、Java SE8 以降だったら以下のような書き方ができる。
public static void main(String[] args) {
PC pc=new PC();//PCインスタンスを作成
pc.executeUSB(new UsbMemory());//->メモリに書き込みます
pc.executeUSB(new IUsb(){
@Override
public void execute(){
System.out.println("扇風機を回します");
}
});
pc.executeUSB(()->System.out.println("カードを読み込みます"));
}
はぁ?といった感じだがこれはラムダ式といって先程匿名クラスでやった処理をさらに簡略化したものだ。もやはIUsbインターフェイスまでもが隠蔽されてしまった。今回この部分の解説は行わないが、近々記事にする予定だ。楽しみにしていてもらいたい。
コメント