1. ホーム
  2. java

[解決済み] Java8: java.lang.Objectのメソッドにデフォルトメソッドを定義することはなぜ禁じられているのでしょうか?

2022-05-06 06:18:20

質問

デフォルト・メソッドは、Javaのツールボックスの中の素晴らしい新しいツールです。しかし、私は、このメソッドを定義するインターフェイスを書こうとしました。 default のバージョンです。 toString メソッドを使用します。で宣言されたメソッドは、Javaはこれが禁じられていると教えてくれました。 java.lang.Objectdefault 編です。なぜこのようなことが起こるのでしょうか?

ベースクラスが常に勝つというルールがあることは知っています。 default の実装は Object のメソッドで上書きされてしまいます。 Object ということです。しかし、私は、このように Object を仕様に追加しました。特に toString は、デフォルトの実装があると非常に便利かもしれません。

では、なぜJavaの設計者が default のメソッドをオーバーライドします。 Object ?

解決方法は?

これは、言語設計の問題の1つで、明らかに良いアイデアと思われるものですが、調査を始めると、実は悪いアイデアであることに気づきます。

このメール このテーマについては、他のテーマも含めて、多くのことが書かれています。

  • 継承モデルをシンプルにしたい。
  • 明らかな例を見ても、(たとえば AbstractList equal/hashCode/toStringの継承は単一継承とステートに強く結びついており、インターフェースは多重継承とステートレスであることに気付きます。
  • 意外な動作への扉を開く可能性があること。

継承と衝突解決のルールは非常にシンプルに設計されています(クラスはインターフェースに勝ち、派生インターフェースはスーパーインターフェースに勝ち、その他の衝突は実装クラスが解決する)。 もちろん、これらのルールは例外を作るために微調整することができますが、その糸を引っ張り始めると、増加する複雑さはあなたが考えるほど小さくはないことに気づくと思います。

もちろん、より複雑であることを正当化できるようなメリットがあればいいのですが、この場合はそれがありません。 ここで話題にしているのは、equals、hashCode、toStringの3つのメソッドです。 これらのメソッドはすべて本質的にオブジェクトの状態についてであり、そのクラスにとって平等が何を意味するかを決定するのに最適な立場にあるのは、インターフェースではなく、その状態を所有するクラスです(特に平等に関する契約は非常に強いので、いくつかの驚くべき結果については 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 は、別のメンテナンス・ドメインのインターフェイスによって、共通のメソッドのデフォルトを追加することで、壊れてしまったのです。

デフォルトはデフォルトであることが前提です。 デフォルトがないインターフェースにデフォルトを追加しても、(階層のどこにいても)具体的な実装クラスのセマンティクスに影響を及ぼすべきではないのです。 しかし、もしデフォルトがオブジェクトのメソッドをオーバーライドすることができるのであれば、それは真実ではありません。

そのため、一見無害な機能のように見えますが、実際には非常に有害です。わずかな表現力の増加のために多くの複雑さを追加し、個別にコンパイルされたインターフェースに対する善意の無害に見える変更が、実装クラスの意図したセマンティクスを損なうことがあまりにも容易になってしまうのです。