2011-08-20 3 views
2

は、私は次の形式のモデルクラスを持っている:私のequals/hashCodeメソッドはオブジェクトIDより多くを調べるべきですか?私のアプリケーションで

class Book 
{ 
    private int ID; 
    private String title; 

    //other code 
} 

は今、私の質問は2つの一部です:

  1. はイコール()メソッドの以下の良い実装ですか?

    public boolean equals(Object o) 
    { 
        if(o == null) 
        { 
         return false; 
        } 
    
        if(!(o instanceof Book)) 
        { 
         return false; 
        } 
    
        Book other = (Book)o; 
    
        if(o.getID() == ID) 
        { 
         return true; 
        } 
        return false; 
    } 
    

    私はイコール()の実装は、主に私の アプリケーションのビジネスロジックに依存していることを知っています。しかし、2つの書籍のIDが同じ場合、 は理想的には同じ本でなければなりません。したがって、 については、他の値フィールドと同等かどうかをチェックするかどうか混乱します。 [タイトル、価格など]。

  2. が、これはのhashCode()メソッドの良い実装です:

    public int hashCode() 
    { 
        return ID; 
    } 
    

    私の考えは異なる本が異なるIDを持っていますし、 2冊は、彼らが等しい同じIDを持っている場合ということです。したがって、上記の の実装は、私のアプリケーションの コンテキストでのハッシュコードの適切な配布を保証します。

    if(o.getID() == ID) 
    

    IDIntegerオブジェクトではなく、原始的である:

+0

このクラスをHibernateまたはJPAで使用しますか? – Ralph

+0

ほとんどの場合、休止状態です。何か違いはありますか? – user801138

答えて

3

Hibernateを使用している場合は、Hibernate関連の懸案事項を考慮する必要があります。

レイジーロード用のプロキシを作成するHibernate。

  • 常にそれが通常のアプリケーションでif (!this.getClass().equals(o.getClass())) { return false;}を使用することが正しくても、それは休止状態プロキシ(および他のすべてのプロキシ)のために失敗します
  • (あなたがすでにあることを行って)他のオブジェクトのプロパティにアクセスするためにゲッターを使用。その理由は、2つのうちの1つがプロキシである場合、クラスは決して等しくないからです。したがって、テストif(!(o instanceof Book)){return false;}が必要です。

あなたが実装することができ、このクラスの助けを借りてorg.hibernate.proxy.HibernateProxyHelper.getClassWithoutInitializingProxy()を見ているよりも、対称な方法でそれをしたい場合:

if (!HibernateProxyHelper.getClassWithoutInitializingProxy(this) 
    .equals(HibernateProxyHelper.getClassWithoutInitializingProxy(o))) { 
    return false; 
} 
  • 他の問題は多分IDであります - idには新しいオブジェクトの作成ではなく、後でそれらを保存する間に問題が発生する可能性があります。このシナリオを前提とします。id = 0の新しいブックを作成し、ブックをHashSetに入れます(ハッシュコードに応じてハッシュセットのバケットに割り当てられます)。その後、ブックをデータベースに格納し、IDが設定されます。これはハッシュコードを変更するため、エンティティをセット内で再び見つけるために問題が発生します。 - これが問題であるかどうかは、アプリケーション、アーキテクチャ、および休止状態の使用方法に大きく依存します。
+0

+1の問題については、私は同じ行に沿って考えていました。 –

3

はこれをしないでください。 ==を使用して2つの異なるが同じIntegerオブジェクトを比較すると、falseが返されます。

使用この:

if(o.getID().equals(ID)) 

はまたIDnullであることをチェックする必要があると思います。

これ以外にも、あなたのロジックはうまくいきます.2つの等しいオブジェクトに同じハッシュコードが必要であるという契約を堅持しています。そして、等価性の意味についてのビジネスロジックの決定を行いました。あなたは作ることができます(正解はありません)。

+0

その部分を修正しました。 :) – user801138

1

if(o.getID() == ID) ... 

のような二つの整数のアイデンティティのためにこのテストを比較することは良いアイデアではありません。何が欲しいのは平等のためのテストです:

if(ID!=null && ID.equals(o.getID())) ... 
+0

ありがとう、私はintに整数を修正しました。ハッシュコードに関するコメント? – user801138

+0

@ user801138すでに述べたように、スカフマンはうまく見えます。簡潔な方法については+1 – Howard

1

ただ、注意:これ以外

public boolean equals(Object o) { 
    return (o instanceof Book) && 
     ((Book)o).getID == ID; 
} 

:あなたのequalsメソッド

public boolean equals(Object o) 
{ 
    if(o == null) 
    { 
     return false; 
    } 

    if(!(o instanceof Book)) 
    { 
     return false; 
    } 

    Book other = (Book)o; 

    if(other.getID() == ID) 
    { 
     return true; 
    } 
    return false; 
} 

は(同等)のように書かれて短くすることができますあなたのIDが書籍ごとに異なる場合(同じ書籍についても同じ)、これは良い実装です。

(しかし、JB Nizetの発言に注意してください。これは対称のままを確認してくださいequals(またはクラス全体)finalを作るために)依存

+0

+1。 Objectofがnullの場合、instanceofはfalseを返すので、特にnullチェックが冗長です。 – Kal

0

私はあなたの新しい2冊

、あなたは以下の条件を扱うことができるならば、実装のこの種は、OKだと思う、これら2冊は同じタイトルを持っている、「彼らは実際には同じ本ですが、あなたはドン これらの2つの本にはまだIDがありませんので、それらを比較すると等価は下がります

4

これまでの回答にいくつかのコメントを追加したいだけでした。 equalsの契約では、対称でなければならないと述べています。これは、a.equals(b) iff b.equals(a)を意味します。

は通常、equalsで使用されていません(クラスが最終でない場合)。実際にBook(たとえばComicsBook)のサブクラスがequalsをオーバーライドして、他のオブジェクトもComicsBookのインスタンスであることをテストすると、BookインスタンスがComicsBookインスタンスに等しいが、ComicsBookインスタンスがインスタンスBookと等しくない

あなたは、このように(クラスが最終であるか、他のいくつかのまれなケースでの場合を除く)という二つのオブジェクトのクラスを比較する必要があります。

if (this.getClass() != o.getClass()) { 
    return false; 
} 

はところで、それはそれはhashCodeequalsメソッドを生成するときのEclipseが何をするかです。

+0

しかし、Joshua BlochはそうでなければEffective Javaで言います。 –

関連する問題