Java超|インターフェイスの複数実装

親クラスは1つだけ。でも、戦士が背負う奥義の約束は、いくつでも組み合わせられる。

Javaでは、1つのクラスが継承できる親クラスは1つだけです。
つまり、クラスの親を複数持つような多重継承はできません。

しかし、実際のオブジェクト指向では、1つのクラスに複数の能力や役割を持たせたい場面があります。

ドラゴンボールの世界観で考えると、1人の戦士は1つの特徴だけで成り立っているわけではありません。

たとえば、あるオリジナル戦士が次のような力を持っているとします。

性質ドラゴンボール風のイメージ
戦士である戦闘できる
気を解放できるreleaseKi() で気を放てる
戦闘装備を持つshowArmor() で装備情報を示せる
仲間を支援できる治療や補助の力を使える
空中移動できる舞空術のように飛べる

このように、1つのクラスが複数の能力を持つことは自然です。

Javaでは、クラスの親は1つだけに制限されています。
その代わりに、インターフェイスは複数実装できます

この記事では、インターフェイスの複数実装を、ドラゴンボールの世界観で、1人の戦士が複数の奥義契約を同時に引き受けるしくみとして解説します。

Javaではクラスの多重継承はできない

まず、出発点として大切なのは、Javaでは1つのクラスが2つ以上の親クラスを同時に継承できないということです。

たとえば、次のような2つのクラスがあるとします。

class Warrior
{
}

class ArmorUser
{
}

Warrior は戦士としての基本クラスです。
ArmorUser は戦闘装備を使う者としての基本クラスです。

この2つを同時に親クラスとして持つように、次のような書き方はできません。

class SuperSaiyanGuardian extends Warrior, ArmorUser
{
}

Javaのクラス継承では、extends のあとに指定できる親クラスは1つだけです。

書き方Javaで可能か理由
class SuperSaiyanGuardian extends Warrior可能親クラスが1つだけ
class SuperSaiyanGuardian extends Warrior, ArmorUser不可能親クラスを複数指定している

ドラゴンボール風にたとえると、1人の戦士クラスが「サイヤ人戦士の基本クラス」と「装備使いの基本クラス」を、同時に親として持つことはできないということです。

Javaでは、クラスの継承関係は1本の系譜として整理します。
そのため、クラスそのものの多重継承は禁止されています。

なぜクラスの多重継承はできないのか

クラスの多重継承ができると、一見とても便利そうに見えます。

しかし、複数の親クラスを同時に持つと、設計が複雑になりやすいです。

たとえば、2つの親クラスが同じ名前のメソッドを持っていたらどうなるでしょうか。

class Warrior
{
    void show()
    {
        System.out.println("戦士の情報を表示します。");
    }
}

class ArmorUser
{
    void show()
    {
        System.out.println("戦闘装備の情報を表示します。");
    }
}

もし、1つのクラスがこの2つを同時に継承できた場合、show() を呼び出したときに、どちらの show() を使うのか分かりにくくなります。

起こりやすい問題内容
同名メソッドの衝突どちらの親のメソッドを使うか迷う
同名フィールドの衝突どちらの値を指すのか分かりにくい
初期化順序が複雑どの親クラスを先に初期化するのか迷う
設計が読みにくいクラスの責任範囲があいまいになる

ドラゴンボール風にたとえると、1人の戦士が2つの流派の親クラスを同時に受け継ぎ、両方に同じ名前の奥義がある状態です。

たとえば、亀仙流にも show() があり、神流にも show() があるとします。
そのとき、戦士が show() を使ったら、亀仙流の情報表示なのか、神流の情報表示なのか分かりにくくなります。

Javaは、このような混乱を避けるために、クラスの親は1つだけというルールにしています。

図:Javaではクラスの親は1つだけ

この図が示していること

この図では、Javaのクラス継承では親クラスを1つだけ指定できることを表しています。

左側は、SuperSaiyanGuardian が Warrior だけを継承しているので正しい形です。

右側は、SuperSaiyanGuardian が Warrior と ArmorUser の2つを同時に継承しようとしているため、Javaではできない形です。

しくみJavaでの扱い
1つの親クラスを継承できる
複数の親クラスを継承できない

この図から分かることは、Javaではクラスの系譜を1本に保つことで、同名メソッドの衝突や設計の混乱を避けているということです。

それでも複数の能力を持たせたい場面はある

クラスの多重継承ができないとはいえ、1つのクラスに複数の能力を持たせたい場面はたくさんあります。

ドラゴンボール風に考えると、ある戦士は次のような複数の力を持つかもしれません。

持たせたい性質
気を解放できる金色の気を放つ
装備情報を示せる戦闘ジャケットやスカウターを表示する
空を飛べる舞空術で移動する
仲間を支援できる治療や補助を行う

もしクラス継承だけに頼ると、これらを柔軟に組み合わせるのが難しくなります。

そこで Java では、クラスの多重継承は許さない代わりに、インターフェイスの複数実装を使います。

Javaは、次のように役割を分けています。

しくみ役割
クラスの継承親クラスは1つだけにして、構造を整理する
インターフェイスの実装複数の能力や約束を持たせる

この分け方によって、Javaは分かりやすさと柔軟さを両立しています。

ドラゴンボール風に言えば、
戦士としての血筋や土台は1本にする。けれど、身につける奥義や契約は複数持てる
というイメージです。

インターフェイスの複数実装とは何か

Javaでは、1つのクラスが2つ以上のインターフェイスを実装できます。

このときは、implements のあとにインターフェイス名をカンマで並べます。

基本形は次のとおりです。

class クラス名 implements インターフェイス名1, インターフェイス名2
{
}

ドラゴンボール風に、次の2つのインターフェイスを考えます。

インターフェイス役割
iKiUser気を解放する約束
iBattleArmor戦闘装備の情報を示す約束

この2つを、1つの SuperSaiyanGuardian クラスが実装できます。

class SuperSaiyanGuardian implements iKiUser, iBattleArmor
{
}

これは、SuperSaiyanGuardian クラスが次の2つの約束を同時に引き受けるという意味です。

引き受ける約束必要なメソッド
iKiUser の約束releaseKi()
iBattleArmor の約束showArmor()

ドラゴンボール風にたとえると、SuperSaiyanGuardian は、
気を解放できる戦士でもあり、戦闘装備の情報も示せる戦士でもある
ということです。

なぜインターフェイスの複数実装が多重継承の考え方につながるのか

ここで大切なのは、インターフェイスの複数実装は、クラスそのものを複数継承しているわけではないという点です。

複数の親クラスからフィールドや具体的な処理を受け継ぐわけではありません。

受け取るのは、主にメソッド名の約束です。

たとえば、次のような2つのインターフェイスがあるとします。

interface iKiUser
{
    void releaseKi();
}

interface iBattleArmor
{
    void showArmor();
}

この2つを実装するクラスは、releaseKi() と showArmor() の両方を定義しなければなりません。

class SuperSaiyanGuardian implements iKiUser, iBattleArmor
{
    public void releaseKi()
    {
    }

    public void showArmor()
    {
    }
}

つまり、複数のインターフェイスが定めたメソッドのルールを、1つのクラスがまとめて引き受けているわけです。

多重継承の種類Javaでの扱い
複数のクラスを同時に継承するできない
複数のインターフェイスを同時に実装するできる
複数の約束を1つのクラスに持たせるできる

ドラゴンボール風にたとえると、1人の戦士が複数の親を持つのではありません。

そうではなく、
気を解放する契約
戦闘装備を示す契約
のように、複数の奥義契約を同時に守るというイメージです。

だから、インターフェイスの複数実装は、Javaで多重継承の考え方の一部を安全に実現する方法だと考えられます。

ファイル名:Sample4.java

interface iKiUser
{
    void releaseKi();
}

interface iBattleArmor
{
    void showArmor();
}

class SuperSaiyanGuardian implements iKiUser, iBattleArmor
{
    private String name;
    private int battlePower;
    private String armorName;

    public SuperSaiyanGuardian(String n, int bp, String an)
    {
        name = n;
        battlePower = bp;
        armorName = an;
        System.out.println(name + " 戦闘力" + battlePower + "のスーパーサイヤ人守護戦士を作成しました。");
    }

    public void releaseKi()
    {
        System.out.println(name + "が金色の気を解放しました。");
        System.out.println("戦闘力は" + battlePower + "です。");
    }

    public void showArmor()
    {
        System.out.println(name + "の戦闘装備は" + armorName + "です。");
    }
}

class Sample4
{
    public static void main(String[] args)
    {
        SuperSaiyanGuardian warrior1 = new SuperSaiyanGuardian("蒼月", 18000, "青紋バトルジャケット");
        warrior1.releaseKi();
        warrior1.showArmor();
    }
}

実行結果

蒼月 戦闘力18000のスーパーサイヤ人守護戦士を作成しました。
蒼月が金色の気を解放しました。
戦闘力は18000です。
蒼月の戦闘装備は青紋バトルジャケットです。

SuperSaiyanGuardian が2つのインターフェイスを実装している

このプログラムでは、SuperSaiyanGuardian クラスが2つのインターフェイスを実装しています。

class SuperSaiyanGuardian implements iKiUser, iBattleArmor

ここで実装しているのは、次の2つです。

実装しているもの意味
iKiUser気を解放する約束を守る
iBattleArmor戦闘装備の情報を示す約束を守る

つまり SuperSaiyanGuardian は、iKiUser の約束も、iBattleArmor の約束も引き受けています。

そのため、SuperSaiyanGuardian クラスでは、両方のインターフェイスが要求するメソッドを定義する必要があります。

インターフェイス要求するメソッドSuperSaiyanGuardian で定義する必要
iKiUserreleaseKi()必要
iBattleArmorshowArmor()必要

このように、インターフェイスを複数実装するということは、複数の約束を同時に引き受けることです。

ドラゴンボール風にたとえると、SuperSaiyanGuardian は、
気を解放する奥義契約
戦闘装備を示す装備契約
の両方を持つ戦士です。

releaseKi() と showArmor() は何を表しているのか

この例では、2つのインターフェイスが別々の役割を持っています。

interface iKiUser
{
    void releaseKi();
}

iKiUser は、気を解放する約束です。

interface iBattleArmor
{
    void showArmor();
}

iBattleArmor は、戦闘装備の情報を示す約束です。

SuperSaiyanGuardian クラスでは、この2つを次のように実装しています。

public void releaseKi()
{
    System.out.println(name + "が金色の気を解放しました。");
    System.out.println("戦闘力は" + battlePower + "です。");
}

releaseKi() では、戦士が金色の気を解放し、戦闘力を表示しています。

public void showArmor()
{
    System.out.println(name + "の戦闘装備は" + armorName + "です。");
}

showArmor() では、戦闘装備として青紋バトルジャケットを表示しています。

整理すると、次のようになります。

メソッド役割表示内容
releaseKi()気の解放名前、気の解放、戦闘力
showArmor()戦闘装備の情報表示装備名

同じ SuperSaiyanGuardian オブジェクトが、2つの異なる役割を持っていることが分かります。

図:2つのインターフェイスを1つのクラスが実装する

この図が示していること

この図では、iKiUser と iBattleArmor という2つのインターフェイスから、SuperSaiyanGuardian クラスへ約束が集まる様子を表しています。

iKiUser は releaseKi() という約束を持っています。
iBattleArmor は showArmor() という約束を持っています。

SuperSaiyanGuardian は、その両方を implements で実装しています。

インターフェイス約束SuperSaiyanGuardian の責任
iKiUserreleaseKi() を持つreleaseKi() を定義する
iBattleArmorshowArmor() を持つshowArmor() を定義する

この図から分かることは、Javaではクラスの多重継承はできなくても、インターフェイスを使えば複数のメソッドの約束を1つのクラスに集められるということです。

なぜクラスの多重継承より扱いやすいのか

クラスの多重継承では、複数の親クラスから具体的なフィールドやメソッドを受け継ぐことになります。

そのため、同じ名前のメンバがあったときに衝突しやすくなります。

一方、インターフェイスは、主に「こういうメソッドを持つこと」という約束を表します。

そのため、役割を分けやすく、クラス構造も複雑になりにくいです。

しくみ役割
クラスの継承共通の土台を受け継ぐ
インターフェイス能力や約束を追加する

ドラゴンボール風にたとえると、クラスは「SuperSaiyanGuardian という存在そのもの」を表します。

一方、インターフェイスは、次のような能力ルールを表します。

インターフェイス能力ルール
iKiUser気を解放できる
iBattleArmor戦闘装備の情報を示せる

つまり、クラスで「何者か」を表し、インターフェイスで「何ができるか」を追加しているわけです。

この整理があるので、Javaではクラスの多重継承を使わなくても、複数の能力を自然に表現できます。

インターフェイスの複数実装が便利な場面

インターフェイスの複数実装は、1つのクラスに複数の役割を持たせたいときに便利です。

ドラゴンボール風に考えると、次のような使い方ができます。

インターフェイス役割
iKiUser気を解放できる
iBattleArmor戦闘装備の情報を示せる
iFlyable空中移動できる
iHealer仲間を回復できる

たとえば、将来的に SuperSaiyanGuardian に飛行能力の約束も追加したい場合は、次のようにできます。

class SuperSaiyanGuardian implements iKiUser, iBattleArmor, iFlyable
{
}

このように、親クラスを増やさなくても、必要な能力の約束を増やせます。

目的インターフェイスでの表現
気を解放できることを保証したいiKiUser
戦闘装備を示せることを保証したいiBattleArmor
飛行できることを保証したいiFlyable
回復できることを保証したいiHealer

これにより、クラスは1つの基本構造を保ちながら、能力や役割の面では柔軟に広げられます。

抽象クラスとの違いも意識しておきたい

インターフェイスの複数実装を理解するには、抽象クラスとの違いも押さえておくと分かりやすいです。

比較項目抽象クラスインターフェイス
役割共通の土台共通の約束
通常フィールド持てる原則として持てない
通常メソッド持てる原則として処理を書かない
コンストラクタ持てる持てない
継承・実装extends で1つだけimplements で複数可
表しやすいもの何者か何ができるか

ドラゴンボール風にたとえると、抽象クラスは「戦士としての共通の土台」です。

たとえば、名前、戦闘力、修行する処理のような共通状態や共通処理を持たせたい場合に向いています。

一方、インターフェイスは「能力や役割の約束」です。

たとえば、気を解放できる、戦闘装備を示せる、飛べる、仲間を回復できる、といった約束を表します。

使いたい場面向いているもの
共通の状態や処理を持たせたい抽象クラス
複数の能力や約束を持たせたいインターフェイス
1つの親として土台を作りたい抽象クラス
複数の役割を同時に表したいインターフェイス

この違いを意識すると、インターフェイスの複数実装が、なぜ多重継承の考え方につながるのかが見えてきます。

図:クラス継承とインターフェイス複数実装の違い

この図が示していること

この図では、クラス継承とインターフェイス複数実装の違いを比較しています。

左側では、クラス継承は親クラスを1つだけ持てることを表しています。
複数の親クラスから1つの子クラスへ継承する形にはバツ印が付いています。

右側では、SuperSaiyanGuardian が iKiUser と iBattleArmor の2つのインターフェイスを実装しています。

これは、複数の親クラスを持っているのではありません。
複数の約束を引き受けている状態です。

しくみできること
extends親クラスを1つだけ指定できる
implements複数のインターフェイスを指定できる

この図から分かることは、Javaはクラスの構造を1本に保ちながら、インターフェイスによって複数の能力や役割を表現しているということです。

オブジェクト指向らしい自然な設計につながる

オブジェクト指向では、クラスを「何者か」で整理するだけでなく、「何ができるか」で整理することも大切です。

SuperSaiyanGuardian は、スーパーサイヤ人守護戦士という具体的な存在です。

しかし、それだけでなく、次のような能力や役割を持っています。

見方内容
何者かSuperSaiyanGuardian
何ができるかreleaseKi() で気を解放できる
何ができるかshowArmor() で戦闘装備を示せる

この「何ができるか」を表すのがインターフェイスです。

インターフェイスを使うと、現実の考え方に近い形でクラスを整理できます。

ドラゴンボール風にたとえると、1人の戦士は「スーパーサイヤ人守護戦士である」という存在としての分類を持ちながら、次のような複数の役割も持てます。

役割内容
気を解放する戦闘力を高める
装備を示すバトルジャケットの情報を表示する
飛行する空中移動する
仲間を支援する回復や補助を行う

Javaでは、この複数の役割をインターフェイスで表現できます。

ドラゴンボール風にインターフェイスの複数実装を整理する

Javaでは、1つのクラスが複数の親クラスを持つことはできません。
つまり、クラスの多重継承はできません。

しかし、1つのクラスが複数のインターフェイスを実装することはできます。

ドラゴンボール風にたとえると、1人の戦士が複数の親を持つのではありません。

その代わりに、複数の能力や役割の約束を持つことができます。

Javaのしくみドラゴンボール風のイメージ
クラスの親は1つ戦士の系譜は1本
インターフェイスは複数実装できる複数の奥義契約や能力を持てる
iKiUser気を解放する約束
iBattleArmor戦闘装備を示す約束
SuperSaiyanGuardian両方の約束を守る具体的な戦士

つまり、インターフェイスによる複数実装は、
親クラスを増やすのではなく、守るべき約束を増やすことで、多重継承の考え方を安全に表現するしくみ
です。

この感覚がつかめると、Javaがなぜクラスの多重継承を認めず、それでもインターフェイスで柔軟さを残しているのかが自然に見えてきます。

この内容で押さえておきたいポイント

ポイント内容
Javaのクラス継承親クラスは1つだけ
クラスの多重継承Javaではできない
インターフェイスの複数実装1つのクラスで複数指定できる
書き方implements インターフェイス名1, インターフェイス名2
実装クラスの責任すべてのインターフェイスのメソッドを定義する
インターフェイスの役割能力や約束を表す
抽象クラスとの違い抽象クラスは共通の土台、インターフェイスは共通の約束
多重継承の考え方複数の約束を同時に引き受ける形で一部を実現する

インターフェイスの複数実装を使うと、1つのクラスに複数の役割を持たせられます。

SuperSaiyanGuardian は、iKiUser の約束も iBattleArmor の約束も守ります。

そのため、releaseKi() で気を解放でき、showArmor() で戦闘装備の情報も表示できます。

Javaでは親クラスを複数持つことはできません。
しかし、インターフェイスを使えば、複数の能力や約束を安全に組み合わせることができます。