web-dev-qa-db-ja.com

Javaインターフェイスは多重継承をシミュレートしますか?

「The Java Tutorial」(2回目)を読んでいます。インターフェースに関するセクションをもう一度読みましたが、Javaインターフェースが多重継承をどのようにシミュレートするのかまだ理解していません。本にあるものよりも明確な説明はありますか?

74
jacknad

ドメインに2種類の物があると仮定します:トラックとキッチン

トラックにはdriveTo()メソッドがあり、キッチンにはcook()メソッドがあります。

パウリが配達用トラックの後ろからピザを販売することを決めたとします。彼は、driveTo()とcook()で一緒にできることを望んでいます。

C++では、多重継承を使用してこれを行います。

Javaこれはあまりにも危険であると考えられていたため、メインクラスから継承できますが、インターフェースから動作を「継承」できます。メソッドの実装。

したがって、Javaでは、委任を使用して多重継承を実装する傾向があります。

Pauliは、トラックをサブクラス化し、kitchenというメンバー変数でトラックにキッチンを追加します。彼はkitchen.cook()を呼び出すことでKitchenインターフェースを実装します。

class PizzaTruck extends Truck implements Kitchen {
   Kitchen kitchen;

   public void cook(Food foodItem) {
      kitchen.cook(foodItem);
   }
}

彼は今、次のようなことができるので、彼は幸せな男です。

pizzaTruck.driveTo(beach);
pizzaTruck.cook(pizzaWithExtraAnchovies);

わかりました、この馬鹿げた話は、多重継承のシミュレーションではなく、コントラクトのみを継承でき、インターフェイスと呼ばれる空の抽象基本クラスからのみ継承できるという条件付きの真の多重継承であるということを指摘することでした。

(更新: デフォルトメソッドインターフェイス の登場により、継承される動作も提供できるようになりました)

150
Peter Tillemans

1つのクラスが複数の親から実装の詳細を継承するという点で、複数の継承をローカルで表示するため、おそらく混乱するでしょう。これはJavaでは不可能です(また、可能であれば、多くの場合、言語での悪用につながります)。

インターフェースは、複数のtypesの継承を許可します。 class Waterfowl extends Bird implements Swimmerは、あたかもBirdであるかのように他のクラスで使用できます-andあたかもSwimmerであるかのようにこれは、多重継承のより深い意味です。つまり、1つのオブジェクトが一度に複数の無関係な異なるクラスに属するように振る舞うことができます。

18

Javaのインターフェースを介して複数の継承を実現する方法を次に示します。

達成すべきこと
クラスAはB、Cを拡張します//これはJavaで直接は不可能ですが、間接的に実現できます。

class B{
   public void getValueB(){}
}

class C{
   public void getValueC(){}
}


interface cInterface{
   public getValueC();
}

class cChild extends C implemets cInterface{
    public getValueC(){

      // implementation goes here, call the super class's getValueC();

    }
}


// Below code is **like** class A extends B, C 
class A extends B implements cInterface{
   cInterface child =  new cChild();
   child.getValueC();
}
16
challenger

以下の2つのインターフェイスが与えられた場合...

interface I1 {
  abstract void test(int i);
}
interface I2 {
  abstract void test(String s);
}

以下のコードを使用して、これらの両方を実装できます...

public class MultInterfaces implements I1, I2 {
  public void test(int i) {
    System.out.println("In MultInterfaces.I1.test");
  }
  public void test(String s) {
    System.out.println("In MultInterfaces.I2.test");
  }
  public static void main(String[] a) {
    MultInterfaces t = new MultInterfaces();
    t.test(42);
    t.test("Hello");
  }
}

2つのオブジェクトを拡張することはできませんが、2つのインターフェイスを実装できます。

10
david99world

インターフェイスは多重継承をシミュレートしません。 Java作成者は多重継承を間違っていると考えたため、Javaにはそのようなことはありません。

2つのクラスの機能を1つに結合する場合-オブジェクト構成を使用します。つまり.

public class Main {
    private Component1 component1 = new Component1();    
    private Component2 component2 = new Component2();
}

また、特定のメソッドを公開する場合は、それらを定義し、対応するコントローラーに呼び出しを委任します。

ここでインターフェースが便利になるかもしれません-Component1インターフェースを実装しますInterface1およびComponent2実装Interface2、定義できます

class Main implements Interface1, Interface2

そのため、コンテキストで許可されている場合は、オブジェクトを交換可能に使用できます。

10
Bozho

JavaScriptの開発者の観点から、このようなことで一体何が起こっているのかを理解しようとしていますが、いくつかのことを指摘したいと思います。マークオフ方法。

インターフェイスは本当にシンプルです。愚かで、めちゃくちゃ簡単です。人々が最初に考えるほど愚かで、非常に単純です。だからこそ、この正確な主題について非常に多くの重複した質問があります。すべてのJava私がこれまでさらされてきたサーバー側のコードベースで広く使われています。

だから、なぜあなたはそれらを使用したいのですか?ほとんどの場合、そうしません。多くの人が考えているように、あなたは確かに常にそれらを使いたくないでしょう。しかし、あなたがそうする時が来る前に、彼らがそうでないものについて話しましょう。

インターフェースはNOT:

  • 何らかの方法で、Javaに欠けるあらゆる種類の継承メカニズムの回避策です。これらは、継承とは関係がなく、継承したことはなく、継承のようなものをシミュレートしません。
  • 必然的に、あなたが書いたものを支援する何か、それは他の人があなたのものとインターフェースすることを意図した何かを書くのを助けるほどです。

彼らは本当にあなたが一目見ていると思うほど簡単です。人々は常に愚かに誤用しているので、ポイントが何であるかを理解することは困難です。それはただの検証/テストです。インターフェイスに準拠して機能するものを作成したら、その「実装」コードを削除しても何も壊れません。

しかし、インターフェイスを正しく使用している場合は、次の開発者が別のデータベースセットまたはWebサービスのアクセスレイヤーを作成して、アプリの残りの部分を継続するためのツールを提供するため、削除したくないでしょう。使用するのは、クラスが失敗することを知っているからです。100%完成したインターフェイスを所定の場所に配置するまでです。すべてのインターフェイスは、クラスを検証し、約束どおりに実際にインターフェイスを実装していることを確認するだけです。これ以上何もない。

また、ポータブルです。インターフェイス定義を公開することで、非公開コードを使用したい人に、オブジェクトが正しく使用するために準拠するメソッドのセットを提供できます。インターフェイスを実装する必要はありません。彼らはメモ帳にメモを書き留め、それを再確認することができます。しかし、インターフェイスを使用すると、問題のインターフェイスの適切なバージョンが作成されるまで、何も動作しようとしないことが保証されます。

それで、これまでに複数回実装される可能性が低いインターフェイスはありますか?完全に役に立たない。多重継承?その虹に手を伸ばすのをやめる。 Javaそもそもそれらを回避し、合成/集合オブジェクトは多くの点でより柔軟です。それは、インターフェイスが複数の方法でモデル化するのを助けることができないということではありません。継承は許可しますが、実際にはどのような形や形式の継承でもないため、そのように見えるべきではありません。それは、確立したメソッドをすべて実装するまでコードが機能しないことを保証するだけです。

6
Erik Reppen

とても簡単です。 1つのタイプに複数のインターフェースを実装できます。たとえば、ListのインスタンスでもあるDequeの実装を使用できます(およびJava does ...LinkedList )。

実装を複数の親から継承することはできません(つまり、複数のクラスを拡張します)。 宣言(メソッドシグネチャ)は問題ありません。

5
Mark Peters

多重継承のシミュレーションではありません。 Java 2つのクラスから継承することはできませんが、2つのインターフェイスを実装する場合、「2つの異なるクラスから継承したように見えます」。

例えば

interface MyFirstInteface{
    void method1();
}
interface MySecondInteface{
    void method2();
}
class MyClass implements MyFirstInteface, MySecondInteface{
    public void method1(){
        //Method 1
    }
    public void method2(){
        //Method 2
    }

    public static void main(String... args){
        MyFirstInterface mfi = new MyClass();
        MySecondInterface msi = new MyClass();
    }
}

これは機能し、mfiとmsiを使用できます。これは多重継承のようですが、何も継承しないためではなく、インターフェイスによって提供されるパブリックメソッドを書き換えるだけです。

3
Colin Hebert

正確である必要があります:

Javaでは、インターフェイスの多重継承が可能ですが、実装の単一継承のみが可能です。

Javaのようにインターフェイスの多重継承を行います:

public interface Foo
{
    String getX(); 
}

public interface Bar
{
    String getY();
}

public class MultipleInterfaces implements Foo, Bar
{
    private Foo foo;
    private Bar bar;

    public MultipleInterfaces(Foo foo, Bar bar)
    {
        this.foo = foo;
        this.bar = bar;
    }

    public String getX() { return this.foo.getX(); }
    public String getY() { return this.bar.getY(); }
}
3
duffymo

ちなみに、Javaが完全な多重継承を実装しない理由は、あいまいさが生じるためです。「AはB、Cを拡張し、BとCは両方ともfunction "void f(int)"。どの実装がAを継承しますか?Javaのアプローチを使用すると、任意の数のインターフェイスを実装できますが、インターフェイスは署名のみを宣言します。継承するインターフェイスが異なるシグネチャを持つ関数を持っている場合、それらの関数は互いに関係がないため、競合の問題はありません。

これが唯一の方法だとは言っていません。 C++は、実装が優先される優先規則を確立することにより、真の多重継承を実装します。しかし、Javaの著者は、あいまいさを排除することを決定しました。これは、よりクリーンなコードのために作られたという哲学的信念のためか、すべての余分な仕事をしたくないのか、私はしません」わかりません。

3
Jay

多くの実装を簡単に継承できるC++から来た、私を背後から食い止めた何かを指摘したいと思います。

多くのメソッドを備えた「広い」インターフェースを持つことは、具体的なクラスで多くのメソッドを実装する必要があることを意味しますこれらを簡単に共有することはできません実装間で。

例えば:

interface Herbivore {
    void munch(Vegetable v);
};

interface Carnivore {
    void devour(Prey p);
}

interface AllEater : public Herbivore, Carnivore { };

class Fox implements AllEater {
   ... 
};

class Bear implements AllEater {
   ...
};

この例では、FoxとBearは、インターフェースメソッドmunchdevourの両方の共通の基本実装を共有できません。

基本実装が次のように見える場合は、FoxおよびBearに使用することをお勧めします。

class ForestHerbivore implements Herbivore
    void munch(Vegetable v) { ... }
};

class ForestCarnivore implements Carnivore
    void devour(Prey p) { ... }
};

しかし、これらの両方を継承することはできません。基本実装はクラス内のメンバー変数である必要があり、定義されたメソッドはそれに転送できます。つまり:

class Fox implements AllEater {
    private ForestHerbivore m_herbivore;
    private ForestCarnivore m_carnivore;

    void munch(Vegetable v) { m_herbivore.munch(v); }
    void devour(Prey p) { m_carnivore.devour(p); }
}

これは、インターフェースが大きくなると扱いにくくなります(つまり、5-10を超えるメソッド...)

より良いアプローチは、インターフェースをインターフェースの集合として定義することです:

interface AllEater {
    Herbivore asHerbivore();
    Carnivore asCarnivore();
}

つまり、FoxBearはこれら2つのメソッドを実装するだけでよく、インターフェイスと基本クラスは、実装クラスに関連する集約AllEaterインターフェイスから独立して成長できます。

アプリで機能する場合は、この方法で結合を減らします。

2
Macke

実際にインターフェイス自体を実装している場合、複数の具象クラスから「継承」できます。 innerclassesはあなたがそれを達成するのを助けます:

interface IBird {
    public void layEgg();
}

interface IMammal {
    public void giveMilk();
}

class Bird implements IBird{
    public void layEgg() {
        System.out.println("Laying eggs...");
    }
}

class Mammal implements IMammal {
    public void giveMilk() {
        System.out.println("Giving milk...");
    }
}

class Platypus implements IMammal, IBird {

    private class LayingEggAnimal extends Bird {}
    private class GivingMilkAnimal extends Mammal {}

    private LayingEggAnimal layingEggAnimal = new LayingEggAnimal();

    private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal();

    @Override
    public void layEgg() {
        layingEggAnimal.layEgg();
    }

    @Override
    public void giveMilk() {
        givingMilkAnimal.giveMilk();
    }

}
</ code>
2
SHOJAEI BAGHINI

インターフェイスが多重継承を「シミュレートする」と言うのは公平ではありません。

確かに、あなたの型は複数のインターフェースを実装し、多くの異なる型として多態的に振る舞うことができます。ただし、この配置の下で動作または実装を継承することはありません。

一般に、多重継承が必要と思われる構成を見てください。

または多重継承のような何かを達成するための潜在的な解決策は、Mixinインターフェースです http://csis.pace.edu/~bergin/patterns/multipleinheritance.html 。注意して使用してください!

2

彼らはしません。

混乱は、インターフェースの実装が何らかの形の継承を構成すると信じている人々から来ていると思います。そうではありません。実装は単純に空白にすることができ、行為によって強制される動作や契約を通じて保証される動作はありません。典型的な例はClonable-interfaceです。これは多くの優れた機能をほのめかしますが、ほとんど定義されていないため、本質的に役に立たず、潜在的に危険です。

インターフェイスを実装することで何を継承しますか?バケツ!だから、私の意見では、同じ文でインターフェイスと継承という言葉を使うのをやめる。 Michael Borgwardtが言ったように、インターフェイスは定義ではなく側面です。

2
mikek

いいえ、Javaは多重継承をサポートしていません。クラスもインターフェースも使用していません。詳細については、このリンクを参照してください https://devsuyed.wordpress.com/2016/07/ 21/does-Java-support-multiple-inheritance

1
Suyed Dalvi

彼らはそうは思わない。

継承は、具体的には実装間の実装指向の関係です。インターフェイスは実装情報をまったく提供しませんが、代わりにタイプを定義します。継承するには、特定の動作または属性を親クラスから明確に継承する必要があります。

ここでインターフェイスと多重継承の役割について具体的にどこかに質問があると思いますが、今はそれを見つけることができません...

1
Thomas Owens

Javaでは多重継承のサポートはありません。

インターフェースを使用して多重継承をサポートするこのストーリーは、開発者が作成したものです。インターフェースは具体的なクラスよりも柔軟性があり、単一のクラスを使用して複数のインターフェースを実装するオプションがあります。これは、クラスを作成するための2つの設計図に準拠していることに同意するものです。

これは、多重継承に近づこうとしています。ここでは、複数のインターフェイスを実装していますが、ここでは何も拡張(継承)していません。実装クラスは、プロパティと動作を追加するクラスです。親クラスから実装を解放していません。単純に言うと、Javaには多重継承のサポートはありません。

1
Vivek Sadh

Javaには多重継承のシミュレーションは実際にはありません。

クラスごとに複数のインターフェイスを実装できるため、インターフェイスを使用して複数の継承をシミュレートできると言われることもあります。そして、クラスで(継承ではなく)コンポジションを使用して、継承しようとした複数のクラスの動作を実現しますそもそも.

1
Justin Niessner

多重継承が非常に便利で、コードを追加せずにインターフェイスに置き換えるのが難しい場合があります。たとえば、Android Activityから派生したクラスと同じアプリ内のFragmentActivityから派生したクラスを使用するアプリがあります。特定の機能を共通のクラスで共有したい場合は、Java ActivityとFragmentsActivityの子クラスを同じSharedFeatureクラスから派生させる代わりに、コードを複製する必要があります。そして、Java次の記述は違法であるためです。

public class SharedFeature<T> extends <T extends Activity>

...
...
1
Sergiob

また、Javaは多重継承をサポートしていません。

Javaのextendsキーワードとimplementsキーワードの意味を区別する必要があります。 extendsを使用する場合、実際にはそのキーワードの後のクラスを継承します。ただし、すべてを単純にするために、extendsを複数回使用することはできません。ただし、必要な数のインターフェイスを実装できます。

インターフェースを実装する場合、各インターフェースのすべてのメソッドの実装を見逃す可能性はゼロです(例外:Java 8)で導入されたインターフェースメソッドのデフォルト実装)新しいクラスに埋め込んだもので何が起こっているかを完全に認識します。

なぜJavaが多重継承を許可しないのは、実際、多重継承はコードをやや複雑にします。親クラスの2つのメソッドが同じ署名を持っているために競合する場合があります。すべてのメソッドを手動で実装すると、上記で説明したように、何が起こっているのかを完全に理解できます。

Javaインターフェイスに関する詳細情報が必要な場合は、この記事を参照してください http://www.geek-programmer.com/introduction-to-Java-interfaces/

1
user7338196

オブジェクトモデルで意味があれば、もちろん1つのクラスから継承し、1つ以上のインターフェイスを実装することもできます。

1