web-dev-qa-db-ja.com

なぜJavaには多重継承がないのに、複数のインターフェースの実装が許可されているのですか?

Javaは複数の継承を許可しませんが、複数のインターフェースを実装できます。どうして?

143
abson

インターフェイスはwhatがクラスを実行しているだけであり、howが実行しているのではないため。

多重継承の問題は、2つのクラスが異なる方法同じことを行うことを定義し、サブクラスがどちらを選択するか選択できないことです。

210
Bozho

私の大学のインストラクターの一人がこのように説明してくれました。

トースターというクラスと、NuclearBombというクラスがあるとします。どちらにも「暗闇」の設定があります。どちらにもon()メソッドがあります。 (一方にはoff()があり、他方にはありません。)これらの両方のサブクラスであるクラスを作成したい場合...ご覧のように、これは私の顔に本当に爆発する可能性がある問題です。

したがって、主な問題の1つは、2つの親クラスがある場合、同じ機能の異なる実装を持っている可能性があることです。あるいは、私のインストラクターの例のように、同じ名前の2つの異なる機能を持っている可能性があります。次に、サブクラスで使用するものを決定する必要があります。確かにこれを処理する方法はありますが、C++はそうしますが、Javaの設計者は、これによって事態が複雑になりすぎると感じました。

ただし、インターフェイスを使用すると、別のクラスのメソッドを借用するのではなく、クラスが実行できることを記述できます。複数のインターフェイスは、複数の親クラスよりも解決する必要があるトリッキーな競合を引き起こす可能性がはるかに低くなります。

89
Syntactic

ca n'tと言っても「継承は使い古されているので、このメソッドは便利だと思います。そのクラスも拡張します」。

public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter, 
             AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
22

この質問の答えは、Java compiler(constructor chaining)の内部動作にあります。 Javaコンパイラー:

public class Bank {
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank{
 public void printBankBalance(){
    System.out.println("20k");
  }
}

これをコンパイルすると、次のようになります。

public class Bank {
  public Bank(){
   super();
  }
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank {
 SBI(){
   super();
 }
 public void printBankBalance(){
    System.out.println("20k");
  }
}

クラスを拡張し、そのオブジェクトを作成すると、Objectクラスまで1つのコンストラクターチェーンが実行されます。

上記のコードは問題なく実行されます。しかし、Carと呼ばれる別のクラスBankと、SBICarと呼ばれる1つのhybrid(多重継承)クラスがある場合:

class Car extends Bank {
  Car() {
    super();
  }
  public void run(){
    System.out.println("99Km/h");
  }
}
class SBICar extends Bank, Car {
  SBICar() {
    super(); //NOTE: compile time ambiguity.
  }
  public void run() {
    System.out.println("99Km/h");
  }
  public void printBankBalance(){
    System.out.println("20k");
  }
}

この場合、(SBICar)はコンストラクターchain(compile time ambiguity)の作成に失敗します。

インターフェイスの場合、オブジェクトを作成できないため、これは許可されています。

defaultおよびstaticメソッドの新しい概念については、 インターフェイスのデフォルト を参照してください。

これでクエリが解決されることを願っています。ありがとう。

12

複数のインターフェースを実装することは非常に便利であり、言語の実装者やプログラマーに大きな問題を引き起こすことはありません。許可されています。多重継承も有用ですが、ユーザーに深刻な問題を引き起こす可能性があります(恐ろしい 死のダイヤモンド )。また、多重継承を使用して行うほとんどのことは、構成または内部クラスを使用して行うこともできます。したがって、多重継承は、利益よりも多くの問題をもたらすことを禁じられています。

7
Tadeusz Kopec

Javaは、インターフェースを介した多重継承のみをサポートします。クラスは任意の数のインターフェイスを実装できますが、拡張できるクラスは1つだけです。

多重継承は致命的なダイヤモンドの問題につながるため、サポートされていません。ただし、解決することはできますが、システムが複雑になるため、Javaファウンダーによって多重継承が削除されました。

1995年2月のジェームズゴスリングによる「Java:an Overview」というタイトルのホワイトペーパー( link )は、多重継承がJavaでサポートされない理由を示しています。

ゴスリングによると:

「Javaは、経験上、メリットよりも悲しみをもたらすC++のめったに使用されない、よく理解されていない混乱する機能の多くを省略します。これは、主に演算子オーバーロード

4
Praveen Kumar

同じ理由で、C#は複数の継承を許可しませんが、複数のインターフェイスを実装できます。

多重継承を備えたC++から学んだ教訓は、それが価値以上の問題を引き起こすということでした。

インターフェースは、クラスが実装しなければならないものの契約です。インターフェイスから機能を取得することはありません。継承を使用すると、親クラスの機能を継承できます(また、多重継承では、非常に混乱する可能性があります)。

複数のインターフェイスを許可すると、デザインパターン(アダプターなど)を使用して、多重継承を使用して解決できる同じタイプの問題を、はるかに信頼性が高く予測可能な方法で解決できます。

3
Justin Niessner

多重継承 に関するOracleドキュメントのページで、このクエリの正確な答えを見つけることができます

  1. 複数の状態の継承:複数のクラスからフィールドを継承する機能

    Javaプログラミング言語が複数のクラスの拡張を許可しない理由の1つは、状態の多重継承の問題を回避することです。これは、複数のクラスからフィールドを継承する機能です

    複数の継承が許可されている場合、そのクラスをインスタンス化してオブジェクトを作成すると、そのオブジェクトはクラスのすべてのスーパークラスからフィールドを継承します。 2つの問題が発生します。

    1. 異なるスーパークラスのメソッドまたはコンストラクターが同じフィールドをインスタンス化する場合はどうなりますか?
    2. どのメソッドまたはコンストラクターが優先されますか?
  2. 実装の複数の継承:複数のクラスからメソッド定義を継承する機能

    このアプローチの問題:name conflictsおよびambiguity。サブクラスとスーパークラスに同じメソッド名(およびシグネチャ)が含まれている場合、コンパイラは呼び出すバージョンを決定できません。

    ただし、Javaは、このタイプの多重継承を デフォルトメソッド でサポートしています。これはJava 8リリース以降に導入されました。 Javaコンパイラは、特定のクラスが使用するデフォルトのメソッドを決定するためのいくつかのルールを提供します。

    ダイヤモンドの問題を解決する方法の詳細については、以下のSEの投稿を参照してください。

    Java 8の抽象クラスとインターフェースの違いは何ですか?

  3. タイプの多重継承:クラスが複数のインターフェースを実装する能力。

    インターフェイスには変更可能なフィールドが含まれていないため、ここで状態を複数継承することで生じる問題を心配する必要はありません。

3
Ravindra babu

オブジェクトの状態は、その中のフィールドに関して参照されると言われ、あまりにも多くのクラスが継承されるとあいまいになります。リンクはこちら

http://docs.Oracle.com/javase/tutorial/Java/IandI/multipleinheritance.html

2
Karthik GVD

たとえば、同じメソッドm1()を持つ2つのクラスA、B。また、クラスCはA、Bの両方を拡張します。

 class C extends A, B // for explaining purpose.

これで、クラスCはm1の定義を検索します。最初に、見つからなかった場合はクラス内で検索し、その後、親クラスにチェックします。 A、Bの両方が定義を持っているので、ここではどちらの定義を選択すべきかという曖昧さが生じます。したがって、Javaは複数の継承をサポートしません。

1
Pooja Khatri

Javaは、次の2つの理由により、多重継承をサポートしていません。

  1. Javaでは、すべてのクラスはObjectクラスの子です。サブクラスが複数のスーパークラスから継承する場合、サブクラスはオブジェクトクラスのプロパティを取得するあいまいさを取得します。
  2. Javaでは、明示的に記述するか、まったく記述しない場合、すべてのクラスにコンストラクターがあります。最初のステートメントは、super()を呼び出して、夕食クラスのコンストラクターを呼び出します。クラスに複数のスーパークラスがある場合、混乱します。

したがって、1つのクラスが複数のスーパークラスから拡張されると、コンパイル時エラーが発生します。

1
raghu.g.b Raghu

Test1、Test2、およびTest3が3つのクラスであるシナリオを考えます。 Test3クラスは、Test2およびTest1クラスを継承します。 Test1クラスとTest2クラスに同じメソッドがあり、それを子クラスオブジェクトから呼び出す場合、Test1またはTest2クラスのメソッドを呼び出すことはあいまいになりますが、インターフェイスには実装のないようなあいまいさはありません。

0
Nikhil Kumar

インターフェースは単なる契約だからです。そして、クラスは実際にはデータのコンテナです。

0
Snake

あいまいさの問題のため、Javaは多重継承、マルチパス、ハイブリッド継承をサポートしていません:

 Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so  C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ?  So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.

多重継承

参照リンク:https://plus.google.com/u/0/communities/102217496457095083679

0
user7445071

たとえば、クラスAにgetSomethingメソッドがあり、クラスBにgetSomethingメソッドがあり、クラスCがAとBを拡張する場合を考えてみましょう。誰かがC.getSomethingを呼び出した場合はどうなりますか?呼び出すメソッドを決定する方法はありません。

インターフェイスは基本的に、実装クラスに含める必要があるメソッドを指定するだけです。複数のインターフェイスを実装するクラスは、クラスがそれらすべてのインターフェイスからメソッドを実装する必要があることを意味します。 Whciは上記のような問題を引き起こしません。

0
John Kane