Javaはなぜ複数の親を継承できないのか
リンク:https://www.zhihu.com/question/21476063/answer/18351313 出典:著作権は作者の所有であることを知っている.商業転載は著者に連絡して許可を得てください.非商業転載は出典を明記してください.
多重継承は複雑で問題が発生しやすい機能です.それはGoto文と同じように、利害が交錯しています.以下に2つの部分に分けて述べます.第1部はPython多重継承が直面したトラブルで、第2部はJavaとRubyが多重継承需要をどのように折衷するかです.
第1部
Pythonは多重継承をサポートしていますが、多重継承の方法で順序を探す問題(MROと呼ばれています)を解決するために、苦難の歴史があります.
1.従来モデル
深度優先アルゴリズム(および、左から右)を直接使用して、各クラスが最初に現れる位置を選択します.たとえば
Dクラスの一例として、そのメンバーの検索順序は、D、B、A、Cである.しかし、次のような「菱形継承」に遭遇すると面倒になります.
Dクラスの一例として,探索順序もD,B,A,Cであるが,そのsaveメソッドを呼び出す場合,果たしてAを呼び出すのであろうか.それともCの中のですか?直感的に見ると、Cのはずです.ここに矛盾が生じた.
2.Python 2.2のnew-style classモード
Python 2.2にはnew-style classが導入されており、javaのようにすべてのクラスが最も根本的なobjectクラスから継承されていることが明らかになった.これは「菱形継承」を非常に普遍化させ、MRO戦略を変えるしかない.深度優先検索を使用して左から右に移動しますが、各クラスは最後に表示される場所を選択します.これにより、上の「菱形継承」の処理が完璧になり、形成される順序は、D、B、C、Aであり、共通の基礎類であればあるほど、後ろに置かれる.しかし、クロス継承に遭遇すると、ここでは、XもYもO、A継承(X、Y)(注意、前後順あり)、B継承(Y、X)、さらに一番下のクラス継承(A、B)から継承されている.上記のアルゴリズムに従って出た結果は:?、A、B、Y、X、O.これはちょっとおかしいですね.AはBの前に、Aが受け継いだXはYの前にあるのに、なぜXの優先度がYより低いのですか.
3.C 3アルゴリズム
1996年、牛人たちはA monotonic superclass linearization for Dylanという文章を書いて、階層計算に基づく線形MROアルゴリズムを提供して、C 3と呼ばれて、全体的に合理的です.(アルゴリズムは詳しくは言わない)2012年にDylan言語、2007年にPython 2.3に加入したほか、Perl 6、Parrotなどの言語もある.このように計算問題は基本的に解決されたとはいえ、多重継承自体には疑問な点がたくさんあります.例えば、
第2部
多重継承はそんなに複雑だが、単一継承はそんなに拘束されているのに、どうすればいいのだろうか.
1.インタフェースの継承
Javaは,単一の継承クラス(メソッドの実装)のみを許可するが,複数のインタフェース(メソッドの定義)を継承することができる.
Javaのインタフェース継承機能は,静的言語の多重継承性を実現するとともに,多重継承のデータ構造の衝突とクラス階層の複雑さを回避する.しかし、インタフェースが問題を解決する完璧な方法だとは言えません.インタフェースは実装を共有できないという欠点もある.本来は継承階層を越えてコードを共有するためだけであったが,現在は別の独立したオブジェクトを生成する必要があり,メソッド呼び出しのたびにこのオブジェクトに委任する必要があるのはあまり合理的ではなく,実行の効率も高くない.『松本行弘のプログラムワールド』
2. Mix-in
これはルビーが推奨していたもので、最初はLispで使われていました.ルールは次のとおりです.通常の継承は単一の継承です.2番目と2つ以上の親はMix-inの抽象クラスでなければなりません(つまり、インスタンスを単独で生成することはできません.通常のクラスを継承することはできません).このルールでは,単一継承構造を維持することができ,またMix−inでメソッドの実装を共有することができる.
結論
多重継承の実装方法.多くの人が言っているように、複数のインタフェースを実装して実装すべきではありません.もしそうなら、大量の「CTRL C+CTRL V」が発生し、大量のCTRL C+CTRL+Vを発見したとき、ほとんど断定することができます.あなたのコードはよく書けません.まず,Thinking in Javaでは,著者らは,継承ではなく組合せを優先すべきであると判断した場合,多態(サブクラスを親に変える)を必要としない.なぜなら、継承自体が複雑で面倒で慎重なことだと思います.何人の牛が相手にツッコミを入れているのだろうか.
「実装上の継承はgoto文を過度に使用することと同様に、プログラムをねじ曲げたり脆弱にしたりする.結果として、オブジェクト向けシステムは通常複雑で多重化の欠如に苦しんでいる」-John Ousterhout(Tcl and Tkの創始者)Scripting,IEEE Computer,March 1998
「オブジェクト向けプログラミング言語の問題は、常に必要なすべての隠れた環境を備えていることです.バナナがほしいですが、ゴリラがバナナを持っていて、ジャングル全体を持っています」Joe Armstrong(Erlang言語発明者)
多重継承は複雑で問題が発生しやすい機能です.それはGoto文と同じように、利害が交錯しています.以下に2つの部分に分けて述べます.第1部はPython多重継承が直面したトラブルで、第2部はJavaとRubyが多重継承需要をどのように折衷するかです.
第1部
Pythonは多重継承をサポートしていますが、多重継承の方法で順序を探す問題(MROと呼ばれています)を解決するために、苦難の歴史があります.
1.従来モデル
深度優先アルゴリズム(および、左から右)を直接使用して、各クラスが最初に現れる位置を選択します.たとえば
class A:
def save(self): pass
class B(A): pass
class C:
def save(self): pass
class D(B, C): pass
Dクラスの一例として、そのメンバーの検索順序は、D、B、A、Cである.しかし、次のような「菱形継承」に遭遇すると面倒になります.
class A:
def save(self): pass
class B(A): pass
class C(A):
def save(self): pass
class D(B, C): pass
Dクラスの一例として,探索順序もD,B,A,Cであるが,そのsaveメソッドを呼び出す場合,果たしてAを呼び出すのであろうか.それともCの中のですか?直感的に見ると、Cのはずです.ここに矛盾が生じた.
2.Python 2.2のnew-style classモード
Python 2.2にはnew-style classが導入されており、javaのようにすべてのクラスが最も根本的なobjectクラスから継承されていることが明らかになった.これは「菱形継承」を非常に普遍化させ、MRO戦略を変えるしかない.深度優先検索を使用して左から右に移動しますが、各クラスは最後に表示される場所を選択します.これにより、上の「菱形継承」の処理が完璧になり、形成される順序は、D、B、C、Aであり、共通の基礎類であればあるほど、後ろに置かれる.しかし、クロス継承に遭遇すると、ここでは、XもYもO、A継承(X、Y)(注意、前後順あり)、B継承(Y、X)、さらに一番下のクラス継承(A、B)から継承されている.上記のアルゴリズムに従って出た結果は:?、A、B、Y、X、O.これはちょっとおかしいですね.AはBの前に、Aが受け継いだXはYの前にあるのに、なぜXの優先度がYより低いのですか.
3.C 3アルゴリズム
1996年、牛人たちはA monotonic superclass linearization for Dylanという文章を書いて、階層計算に基づく線形MROアルゴリズムを提供して、C 3と呼ばれて、全体的に合理的です.(アルゴリズムは詳しくは言わない)2012年にDylan言語、2007年にPython 2.3に加入したほか、Perl 6、Parrotなどの言語もある.このように計算問題は基本的に解決されたとはいえ、多重継承自体には疑問な点がたくさんあります.例えば、
第2部
多重継承はそんなに複雑だが、単一継承はそんなに拘束されているのに、どうすればいいのだろうか.
1.インタフェースの継承
Javaは,単一の継承クラス(メソッドの実装)のみを許可するが,複数のインタフェース(メソッドの定義)を継承することができる.
Javaのインタフェース継承機能は,静的言語の多重継承性を実現するとともに,多重継承のデータ構造の衝突とクラス階層の複雑さを回避する.しかし、インタフェースが問題を解決する完璧な方法だとは言えません.インタフェースは実装を共有できないという欠点もある.本来は継承階層を越えてコードを共有するためだけであったが,現在は別の独立したオブジェクトを生成する必要があり,メソッド呼び出しのたびにこのオブジェクトに委任する必要があるのはあまり合理的ではなく,実行の効率も高くない.『松本行弘のプログラムワールド』
2. Mix-in
これはルビーが推奨していたもので、最初はLispで使われていました.ルールは次のとおりです.通常の継承は単一の継承です.2番目と2つ以上の親はMix-inの抽象クラスでなければなりません(つまり、インスタンスを単独で生成することはできません.通常のクラスを継承することはできません).このルールでは,単一継承構造を維持することができ,またMix−inでメソッドの実装を共有することができる.
結論
多重継承の実装方法.多くの人が言っているように、複数のインタフェースを実装して実装すべきではありません.もしそうなら、大量の「CTRL C+CTRL V」が発生し、大量のCTRL C+CTRL+Vを発見したとき、ほとんど断定することができます.あなたのコードはよく書けません.まず,Thinking in Javaでは,著者らは,継承ではなく組合せを優先すべきであると判断した場合,多態(サブクラスを親に変える)を必要としない.なぜなら、継承自体が複雑で面倒で慎重なことだと思います.何人の牛が相手にツッコミを入れているのだろうか.
「実装上の継承はgoto文を過度に使用することと同様に、プログラムをねじ曲げたり脆弱にしたりする.結果として、オブジェクト向けシステムは通常複雑で多重化の欠如に苦しんでいる」-John Ousterhout(Tcl and Tkの創始者)Scripting,IEEE Computer,March 1998
「オブジェクト向けプログラミング言語の問題は、常に必要なすべての隠れた環境を備えていることです.バナナがほしいですが、ゴリラがバナナを持っていて、ジャングル全体を持っています」Joe Armstrong(Erlang言語発明者)