これは、掘り下げ始めるまで「明らかに良いアイデア」と思われる言語設計の問題のもう 1 つです。実際には悪いアイデアであることがわかります。
このメールには、このテーマ (およびその他のテーマ) について多くのことが書かれています。現在のデザインに至るまでにいくつかの設計上の力が集まりました。
- 継承モデルをシンプルに保ちたいという欲求。
- 明白な例 (たとえば、インターフェースへの変換) を一度見れば、
AbstractList
equals/hashCode/toString の継承は単一の継承と状態に強く結びついており、インターフェースは多重継承されステートレスであることがわかります。
- いくつかの驚くべき行動への扉を開いた可能性があること。
「シンプルに保つ」という目標については既に触れました。継承と競合解決のルールは非常に単純になるように設計されています (クラスはインターフェイスに勝ち、派生インターフェイスはスーパーインターフェイスに勝ち、その他の競合は実装クラスによって解決されます)。もちろん、これらのルールを微調整して例外を作成することもできますが、その文字列を引っ張り始めると、増分の複雑さが思ったほど小さくないことがわかると思います。
もちろん、より複雑にすることを正当化するある程度の利点はありますが、この場合はありません。ここで話しているメソッドは、equals、hashCode、および toString です。これらのメソッドはすべて本質的にオブジェクトの状態に関するものであり、インターフェイスではなく状態を所有するのはクラスであり、そのクラスにとって等価が何を意味するかを判断するのに最適な立場にあるのはクラスです (特に、等価の契約は非常に強力であるため、Effective を参照してください)。いくつかの驚くべき結果のための Java); インターフェースの作成者は、取り除かれすぎています。
AbstractList
この例を引き出すのは簡単です。AbstractList
動作を取り除き、List
インターフェイスに入れることができれば素晴らしいことです。しかし、この明白な例を超えると、他の良い例はあまり見つかりません。ルートでAbstractList
は、単一継承用に設計されています。ただし、インターフェイスは多重継承用に設計する必要があります。
さらに、このクラスを書いていると想像してください:
class Foo implements com.libraryA.Bar, com.libraryB.Moo {
// Implementation of Foo, that does NOT override equals
}
ライターはスーパータイプを調べ、Foo
equals の実装がないことを確認し、参照の等価性を得るために必要なことは から equals を継承することだけであると結論付けObject
ます。それから、来週、Bar のライブラリ管理者が「親切にも」デフォルトのequals
実装を追加します。おっと!のセマンティクスはFoo
、別の保守ドメインのインターフェースによって「役立つ」共通メソッドのデフォルトを追加することで壊れています。
デフォルトはデフォルトであると想定されています。(階層内のどこにでも) 存在しないインターフェイスにデフォルトを追加しても、具体的な実装クラスのセマンティクスに影響を与えるべきではありません。しかし、デフォルトが Object メソッドを「オーバーライド」できるとしたら、それは正しくありません。
したがって、無害な機能のように見えますが、実際には非常に有害です。わずかな増分表現のために多くの複雑さが追加され、個別にコンパイルされたインターフェイスに対する善意の、無害に見える変更が簡単に弱体化されます。クラスを実装する意図されたセマンティクス。