インタフェース(interface)

サブクラスを使って継承をおこなうと,親クラスを対象にしたプログラムがそ のままサブクラスにも適用できるという点で非常に便利である.しかし,単一 のクラスのサブクラスとして,クラス間の関係を木として表現するという考え 方には限界がある.

実際の場面では,単一のクラスの性質だけではなく複数のクラスの性質を受け 継いだクラスを作りたいというケースが出てくることがある.このような要求に 対してダイレクトに答える方法は,複数のクラスを親クラスとするクラスを定義 することを可能にする方法である.これを多重継承(multiple inheritance)と呼 ぶ.

多重継承は自然ではあるが,継承しようとする複数のクラスで同じ名前のメソッ ドが定義されているときに,どの定義に従うかなどの曖昧さが生ずることがあ り,混乱しやすいという問題点がある.Java言語では,多重継承は採用せずに代 わりにインタフェースという仕組みを用意している.

インタフェースはそのインタフェース自体のインスタンスを持たない点で,抽象 クラスと良く似ている.しかし,抽象クラスと違って,メソッドの引数の型,返 り値の型を定義するだけで,中身(実装)は定義できない(abstractメソッドと似ている).インタフェースの定義の例を見てみる.

interface I {
    public void hello(String s);
    public void bye(String s);
}
クラスの継承では「親クラスを継承してサブクラスを作る」と言うが,インタフェースの場合は,「インタフェースを実装(implement)したクラスを作る」と言う.インタフェースIを実装したクラスBの定義の例を見てみる.
class B implements I{
    B(){}
    public void hello(String s){
	System.out.println("Hello "+s+" in B");
    }
    public void bye(String s){
	System.out.println("bye "+s+" in B");
    }
}
あるインタフェースを実装する場合は,そのインタフェースで定義されている すべてのメソッドを定義する必要があるので注意が必要である.

あるクラスは複数のインタフェースを実装することが可能である.インタフェースIとインタフェースJを実装するクラスを定義するときは,

class B implements I,J {
 ... 
}
のように書く.

あるクラスCのサブクラスであり,かつインタフェースIを実装しているクラスD の定義は以下のようにおこなう.

// クラスCのサブクラスでインタフェースIを実装しているクラスDの定義
class D extends C implements I{
    // Dのコンストラクタの宣言
    D(int v){
    // 親クラスCでコントラクタ「C(int v)」が定義されているとしてその呼び出し
	super(v);
    }
    // インタフェースIで宣言されているhelloの実装
    public void hello(String s){
	System.out.println("Hello "+s+" in D("+val+")");
    }
    public void bye(String s){
	System.out.println("Bye "+s+" in D("+val+")");
    }
}
これらをまとめて,テストするプログラム全体は以下のようになる.
interface I{
    public void bye(String s);
    public void hello(String s);
}

class B implements I, J{
    B(){}
    public void hello(String s){
	System.out.println("Hello "+s+" in B");
    }
    public void bye(String s){
	System.out.println("bye "+s+" in B");
    }
}

class C{
    int val;
    C(int v){
	val=v;
    }
    int add(int x){
	val+=x;
	return val;
    }
}

class D extends C implements I{
    D(int v){
	super(v);
    }
    public void hello(String s){
	System.out.println("Hello "+s+" in D("+val+")");
    }
    public void bye(String s){
	System.out.println("Bye "+s+" in D("+val+")");
    }
}

class t{
    static void callHello(I i,String s){
	i.hello(s);
    }
    static void callBye(I i,String s){
	i.bye(s);
    }
    public static void main(String[] args){
	B b=new B();
	callHello(b,"B");
	D d=new D(3);
	callHello(d,args[0]);
	d.add(4);
	callHello(d,args[0]);
	callBye(b,args[0]);
	callBye(d,args[0]);
    }
}
この実行例は以下のようになる.
Macintosh-5:/tmp ktanaka$ java t "tanaka"
Hello B in B
Hello tanaka in D(3)
Hello tanaka in D(7)
インタフェースに関しては,サブインタフェース,インタフェース変数など, さらに細かい話題もあるが,システムで用意されたインタ フェースを実装するクラスを作ることはあるものの,自分でインタフェースを 定義することはあまりないと思われるので,詳しい説明はおこなわない.

例外処理