3

マップとオブジェクトをマップ キーとして使用している場合、デフォルトのハッシュ メソッドと equals メソッドで十分ですか?

class EventInfo{

    private String name;
    private Map<String, Integer> info
 }

次に、マップを作成します。

Map<EventInfo, String> map = new HashMap<EventInfo, String>();

hashCode() と equals() を明示的に実装する必要がありますか? ありがとう。

4

4 に答える 4

6

そうです。HashMapは、キーのハッシュ コードを計算し、それを基点として使用することによって機能します。hashCode関数が (ユーザーによって) オーバーライドされていない場合、メモリ アドレスが使用されequals、 と同じになり==ます。

Eclipse を使用している場合は、それらが生成されます。[ソース] メニュー → [ hashCode() と equals() を生成] をクリックします。

Eclipse をお持ちでない場合は、次の方法で動作するはずです。(上記のように、Eclipse でこれらを生成しました。)

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((info == null) ? 0 : info.hashCode());
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (!(obj instanceof EventInfo)) {
        return false;
    }
    EventInfo other = (EventInfo) obj;
    if (info == null) {
        if (other.info != null) {
            return false;
        }
    } else if (!info.equals(other.info)) {
        return false;
    }
    if (name == null) {
        if (other.name != null) {
            return false;
        }
    } else if (!name.equals(other.name)) {
        return false;
    }
    return true;
}
于 2013-03-12T00:44:10.467 に答える
3

はい、必要です。そうしないと、2つのEventInfoを比較できなくなります(マップは機能しません)。

于 2013-03-12T00:39:45.140 に答える
2

厳密に言えば、いいえ。hashCode() および equals() のデフォルトの実装は、機能するはずの結果を生成します。http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode()を参照してください。

私の理解では、 hashCode() のデフォルトの実装は、メモリ内のオブジェクトのアドレスを取得して整数に変換することで機能し、 equals() のデフォルトの実装は、2 つのオブジェクトが実際に同じオブジェクトである場合にのみ true を返します。

実際には、これらの実装の両方を改善することができます (また、改善する必要があります)。たとえば、どちらのメソッドも、重要でないオブジェクト メンバーを無視する必要があります。さらに、equals() は、オブジェクト内の参照を再帰的に比較したい場合があります。

特定のケースでは、2 つのオブジェクトが同じ文字列を参照するか、2 つの文字列が等しく、2 つのマップが同じか等しい場合、 equals() を true として定義できます。WChargin はかなり良い実装を提供してくれたと思います。

于 2013-03-12T00:45:59.160 に答える
2

何をしたいかによります。同じandを持つ2 つの異なるEventInfoインスタンスが2 つの異なるキーになる場合、 andを実装する必要はありません。nameinfoequalshashCode

そう

EventInfo info1 = new EventInfo();
info1.setName("myname");
info1.setInfo(null);
EventInfo info2 = new EventInfo();
info2.setName("myname");
info2.setInfo(null);

info1.equals(info2)は false をinfo1.hashCode()返し、別の値を に返しますinfo2.hashCode()

したがって、それらをマップに追加する場合:

map.put(info1, "test1");
map.put(info2, "test2");

2 つの異なるエントリがあります。

さて、それは望ましい動作かもしれません。たとえば、EventInfo異なるイベントを収集している場合、同じデータを持つ 2 つの異なるイベントを 2 つの異なるエントリにすることが望ましい場合があります。

equalshashCodeコントラクトは にも適用できますSet

たとえば、イベント情報にマウス クリックが含まれている場合、最終的に次のようになることが望ましい場合があります。

Set<EventInfo> collectedEvents = new HashSet<EventInfo>();
collectedEvents.add(info1);
collectedEvents.add(info2);

収集されたイベントは 1 つではなく 2 つ...

私がここで意味を成していることを願っています...

編集:

ただし、上記のセットとマップに 1 つのエントリのみを含める必要がある場合は、Apache Commons EqualsBuilderHashCodeBuilderequalsを使用して、との実装を簡素化できhashCodeます。

@Override
public boolean equals(Object obj) {
    if (obj instanceof EventInfo) {
        EventInfo other = (EventInfo) obj;
        EqualsBuilder builder = new EqualsBuilder();
        builder.append(name, other.name);
        builder.append(info, other.info);
        return builder.isEquals();
    }
    return false;
}

@Override
public int hashCode() {
    HashCodeBuilder builder = new HashCodeBuilder();
    builder.append(name);
    builder.append(info);
    return builder.toHashCode();
}

EDIT2:

EventInfo2 つのインスタンスが同じと見なされる場合、たとえば、が一意の識別子である場合など、同じ名前を持っている場合も適切ですname(特定のオブジェクトとは少しかけ離れていることはわかっていますが、ここで一般化しています... )

于 2013-03-12T00:47:56.487 に答える