Javaは多重継承をサポートしていません。その代わりに用意しているのがインタフェースという仕組みです。インタフェースの宣言には「interface」キーワードを使います。
Part7のテーマは,ポリモーフィズムをより柔軟に利用するための機能である「インタフェース」です。
Java言語が多重継承を禁止しているということはすでに説明しました。例えば,多重継承が引き起こす問題の一つにダイヤモンド継承があります。スーパークラスを同一とする複数のクラスを継承したときに,それぞれのクラスにスーパークラスから継承した同一シグネチャのメソッドができてしまうという問題です。こうなってしまうと,サブクラスから呼び出すメソッドを特定できなくなってしまいます。
こうした問題はありますが,多重継承はポリモーフィズムをより柔軟に利用するために便利な仕組みでもあります。Java言語はそのためにインタフェースという仕組みを用意しています。いわば,インタフェースはJava版の多重継承なのです。
一部のサブクラスのみで
抽象メソッドをオーバーライドする
例えば,カセットを表現する抽象クラスであるCassetteと,CassetteをスーパークラスとするDeck1クラスとPortable1クラスを想定してください(図1)。Cassetteクラスは,抽象メソッドnameを持っていて,サブクラスであるDeck1とPortable1でnameメソッドをオーバーライドするものとします。
図1を表すサンプル・コードはリスト1のようになります。mainメソッドを持つTest_aクラスで,それぞれのクラスのインスタンスを生成し,printNameメソッドで,ポリモーフィズムを利用してインスタンスごとに異なる文字列を出力しています。
abstract class Cassette {
abstract void name();
}
class Deck1 extends Cassette {
void name() {
System.out.println("カセットデッキ");
}
}
class Portable1 extends Cassette {
void name() {
System.out.println("ポータブルカセット");
}
}
class Test_a {
public static void main(String[] args) {
PrintName(new Deck1());
PrintName(new Portable1());
}
public static void PrintName(Cassette ms) {
ms.name();
}
}
ここで,Deck1クラスとPortable1クラスに,playという新しいメソッドを追加するとしましょう。前回に解説した方法で実現するなら,スーパークラスに抽象メソッドplayを追加するのがよさそうです。そして,二つあるサブクラスのそれぞれでplayメソッドの中身を書いてやればいいわけです。
では,サブクラスが三つ以上で,playメソッドはそのうちの一部のクラスだけに追加したい,という場合はどうでしょう。スーパークラスに抽象メソッドplayを追加すると,playメソッドが必要ないサブクラスでもplayメソッドをオーバーライドしなければならなくなります(図2)。これはムダですね。
多重継承を使えればこの問題はすぐに解決します。まず別の抽象クラスを宣言して,その中で抽象メソッドplayを宣言します。そして,この抽象クラスをplayメソッドを追加するクラスに継承させればよいのです。こうすればCassette2クラスのサブクラスの一部にだけ,playメソッドを持たせられます。多重継承が禁止されているJava言語では,このようなときにインタフェースを使います。
インタフェースでは,メソッドと,そのメソッドが持つべきシグネチャを定義します。メソッドの実体を定義することはできません。抽象クラスのようなものですが,抽象クラスと異なり,多重継承が可能です。すなわち,すでにあるクラスを継承しているクラスに,インタフェースを同時に継承させることもできます。ちなみに普通は,「インタフェースを継承する」とは言わずに,「インタフェースを実装する」と言いますので,以降はこの表現を使います。