Default methods are a nice new tool in our Java toolbox. However, I tried to write an interface that defines a default
version of the toString
method. Java tells me that this is forbidden, since methods declared in java.lang.Object
may not be default
ed. Why is this the case?
I know that there is the "base class always wins" rule, so by default (pun ;), any default
implementation of an Object
method would be overwritten by the method from Object
anyway. However, I see no reason why there shouldn't be an exception for methods from Object
in the spec. Especially for toString
it might be very useful to have a default implementation.
default
では、Java 設計者がのメソッドをオーバーライドするメソッドを許可しないことに決めた理由は何でしょうかObject
?
ベストアンサー1
これは、掘り下げ始めるまでは「明らかに良いアイデア」のように見えるが、実際には悪いアイデアであることに気付く、言語設計の問題の 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 メソッドを「オーバーライド」できる場合、それは当てはまりません。
したがって、これは無害な機能のように見えますが、実際には非常に有害です。つまり、わずかな表現力の向上に対して多くの複雑さが追加され、別々にコンパイルされたインターフェースに対する善意の、一見無害に見える変更によって、実装クラスの意図されたセマンティクスが損なわれる可能性が非常に高くなります。