2011-11-13 6 views
15

これらのメソッドをjava.lang.Objectに含める理由は何ですか?平等とハッシュは多くのクラスにとって意味がありません。ObjectでequalsとhashCodeが定義されているのはなぜですか?

2つのインターフェイスを作るために、より論理的な次のようになります。

interface Equalable { 
    boolean equals(Equalable other); 
} 

interface Hashable extends Equalable { 
    int hashCode(); 
} 

例えばHashSetの定義は、それが一般的な初心者のミスのいずれかを妨げる

class HashSet<T extends Hashable> ... 

のように見えるかもしれません - せずにアイテムのセットを使用してequals/hashCodeを実装しています。

+0

何かの良い記事を見てください[http://msmvps.com/blogs/jon_skeet/archive/2008/12/05/redesigning-system-object-java-lang-object.aspx] (Jon Skeetによる)。 –

+1

リンクが切れているようです。 [This](http://codeblog.jonskeet.uk/2008/12/05/redesigning-system-object-java-lang-object/)は同じ記事かもしれません。 – tkokasih

答えて

13

Interfaceを実装する場合、inject (or accept)というインタフェースで定義された契約です。

Equalable & Hashableは2つの異なる契約です。しかし、我々が密接に見てみると、両者は互いに依存していることがわかります。つまり、それらはの一部であり、EqualableAndHashableのようなものです。

ここで明らかなのは、新しいEqualableAndHashableインターフェイスか、Objectの一部であるかどうかです。

見てみましょう。我々は== (equal operator)を持って2つのオブジェクトの等価性をチェックしています。 ==演算子は、値/参照が2つの異なるプリミティブ/オブジェクトで等しいかどうかを確認します。しかし、これは必ずしも==オペレータで確認するだけで答えることはできません。

ここで、この等価がwhich is also a contractであるかどうかは、インターフェイスまたはObjectクラスの一部を介して注入する必要がありますか?

我々は見てみるならば、私たちはただのようなものと言うことはできません。

TypeXが平等契約を保証するものではありません。

いくつかのオブジェクトタイプが平等を提供し、いくつかのオブジェクトタイプが混乱している場合、混乱となります。つまり、TypeXのオブジェクトは、他のすべてのオブジェクトタイプにも当てはまる等価コントラクトを尊重する必要があります。したがって、等価性は、デフォルトでオブジェクトのコントラクトの一部でなければならないため、インターフェイスからの等価性を注入してはなりません。そうでなければ、混乱が生じます。

equalsの実装では、オブジェクトが必要です。しかし、equalsメソッドだけを実装することはできません。hashcodeメソッドを実装する必要もあります。

+2

'='は実際に代入演算子です;) –

+0

@DaveNewtonありがとうございます。それに応じて変更されました – Kowser

+1

私はあなたが言及している "混乱"を理解していません。私はこれらのメソッドを常に実装して、セットとマップで自分のクラスを使用します。すべてのコストでデフォルトの実装を避ける方が簡単なので、Objectからこれらのメソッドを削除します。 :D –

1

(彼らはインターフェイスにあった場合は個人的に、私はequals/hashCodeミスの少なくとも1つのクラスを避けるために、そこに両方それらを置くところ。)

私はあなたがオブジェクトに実装をしたいと思います、フォールバックメカニズムとして、とにかくインターフェースかどうかにかかわらず、すべてが実装されていることを意味します。

私はそれが歴史的だと思われます。今日のプログラミングJavaは、Javaのプログラミングとはかなり異なっています。

0

一般的な実装です。必要に応じて実装をオーバーライドする必要があります。それ以外の場合は、適切なデフォルト実装があります。

少なくとも等しい必要があります。おそらく、基本的な操作のためのインターフェイスを作成することは、かなりのオーバーヘッドにつながります

+0

あなたのポイントは? – delnan

1

Java 1.0がリリースされたときにジェネリックはまだ存在しませんでした。 2004年にJava 5.0で追加されました。

+2

'Comparator'が指定されていない場合、' TreeSet'が 'Comparable'を実装するためにキーを必要とする可能性がある場合、なぜHashSetは' Hashable'を要求できませんでしたか?ジェネリックよりも多くのことがあります。 – meriton

0

オブジェクトリストがあり、containsメソッドを呼び出す場合、Javaはどうすればいいですか?私はデフォルトの実装(参照を比較)はまともな判断だと思う。この方法では、コレクション内で使用するすべてのクラスに対して自分でequalshashcodeを実装する必要はありません。

1

元来、Javaではジェネリックはありませんでした。これは、Objectを任意のコレクションのメンバーにすることによって回避されました。したがって、ObjectにはいずれもhashCodeおよびequalsが必要です。今は変化するには固執しすぎる。

+0

ジェネリックの不在は無関係です。たとえば、 'Comparator'が指定されていなければ' TreeSet'がキーに 'Comparable'を実装することを要求しないようにしました。 – meriton

2

java.lang.Objectのデフォルト実装は意味があります。しばしば、それは十分です。 JPA/Webアプリケーションでは、equalsやhashCodeをオーバーライドすることはほとんどありません。

String、Longなどの不変値オブジェクトの場合、C#のようにequals()を呼び出すために==演算子をオーバーライドできないのはなぜですか?私はデフォルトのequals/hashCodeが正しいことをしているよりもずっと多くのエラーを見てきました。例えば、

Long x = obj.getId(); 
Long y = obj2.getId(); 
if (x == y) { // oops, probably meant x.equals(y)! } 

それは公正な質問ですが、しかし、なぜデフォルトの方法は、デフォルトObject.clone()のようなタグ付けインターフェイスの後ろにロックされていません。既定の実装がありますが、Cloneableを実装して明示的に使用することを確認する必要があります。 CollectibleやEquatableのような同様のタギングインタフェースも同様に簡単にでき、コレクションメソッドのシグネチャはObjectではなくEquatableであった可能性があります。

0

これは便宜上のことですが、この方法が優れています。さて、あなたは.equalsメソッドを持っていなかった場合は、オブジェクトの平等を行うには取るだろうか考える:

AreEqual(Object obj1,Object obj2) { 
    if(!obj1 instanceof Equalable) return false; 
    if(!obj2 instanceof Equalable) return false; 
    return ((Equalable)(obj1).equals((Equalable)obj2); 
} 

これものhashCodeのために真です。ときには参照平等で十分な場合もあります。 HashSetにHashableを実装するオブジェクトのみを受け入れるようにした場合、参照の平等のみが必要であっても、Hashableクラスを明示的に作成する必要があります。そして、あなたはそれ以外の素晴らしいデータ構造の普遍性を減らしました。

Objectにデフォルトの(そして時には十分な).equals関数と.hashCode関数があり、新しい言語のユーザーにはいくつかの問題が発生することがよくあります。

0

オブジェクトの種類にかかわらず、他のオブジェクトの型がそれが聞こえないものであっても、それが他のオブジェクトと同等かどうかにはっきりと答えることができます。他のオブジェクトの型を聞いたことがない場合、その事実だけで、後者のオブジェクトと同等ではないことを報告するのに十分です。

関連する問題