これは、掘り出しを開始して実際に悪いアイデアであることに気付くまでは、「明らかに良いアイデア」と思われる言語設計の問題のもう1つです。
このメールには、件名(およびその他の件名)に関する多くの情報が含まれています。現在の設計に私たちを導くために収束したいくつかの設計力がありました。
- 継承モデルをシンプルにしたいという願望。
- 明らかな例を過ぎると(たとえば、
AbstractList
インターフェースに変わる)、equals / hashCode / toStringの継承は単一の継承と状態に強く結びついており、インターフェースは多重継承され、ステートレスであることがわかります。
- それが潜在的にいくつかの驚くべき行動への扉を開いたこと。
「シンプルに保つ」という目標についてはすでに触れました。継承と競合解決のルールは非常にシンプルになるように設計されています(クラスはインターフェイスに勝ち、派生インターフェイスはスーパーインターフェイスに勝ちます。その他の競合は実装クラスによって解決されます)。もちろん、これらのルールを微調整して例外を作成することもできますが、そのひもを引っ張り始めると、増分する複雑さが思ったほど小さくはないことがわかるでしょう。
もちろん、より複雑さを正当化するある程度の利点はありますが、この場合はありません。ここで話しているメソッドは、equals、hashCode、およびtoStringです。これらのメソッドはすべて本質的にオブジェクトの状態に関するものであり、そのクラスの等価が何を意味するかを決定するのに最適な位置にあるのは、インターフェイスではなく状態を所有するクラスです(特に、等価のコントラクトは非常に強いため、効果を参照してください)いくつかの驚くべき結果のためのJava); インターフェースライターが削除されすぎています。
このAbstractList
例は簡単に引き出すことができます。AbstractList
動作を取り除いてList
インターフェースに組み込むことができれば、すばらしいでしょう。しかし、この明白な例を超えて移動すると、他に見つかる優れた例は多くありません。ルートでAbstractList
は、単一継承のために設計されています。ただし、インターフェースは多重継承用に設計する必要があります。
さらに、あなたがこのクラスを書いていると想像してください:
class Foo implements com.libraryA.Bar, com.libraryB.Moo {
// Implementation of Foo, that does NOT override equals
}
Foo
スーパータイプで作家のルックスは、対等のない実装を見ないし、その取得するための参照の等価を締結、彼が行う必要があるのは、から継承イコールですObject
。その後、来週、Barのライブラリメンテナがデフォルトのequals
実装を追加しました。おっと!現在、のセマンティクスはFoo
、別のメンテナンスドメインのインターフェースにより、「便利に」一般的なメソッドにデフォルトを追加することで壊れています。
デフォルトはデフォルトです。何もない(階層のどこにでもある)インターフェースにデフォルトを追加しても、具象実装クラスのセマンティクスには影響しません。しかし、デフォルトがObjectメソッドを「オーバーライド」できる場合、それは真実ではありません。
したがって、無害な機能のように見えますが、実際には非常に有害です。少しずつ表現するために複雑さが増し、個別にコンパイルされたインターフェースへの意図的で無害に見える変更を弱体化するのが非常に簡単になります。クラス実装の意図されたセマンティクス