web-dev-qa-db-ja.com

2つのHashMap間の平等

クラスのequals()メソッドでは、プライベートインスタンスHashMap変数を使用して、同等性を比較しています。ただし、HashMap変数を比較すると、2つの異なるオブジェクトが依然として等しいことを示しています。さらなる調査により、リンクに到達しました: ここにリンク 。ただし、HashMap1.equals(HashMap2)が機能しない理由は、「カスタマイズされたコードを記述しない限り、Javaの配列が同等かどうかをテストできないため」というだけです。

私はこの理由を理解していませんでした。誰でも私に手の込んだ理由を教えてもらえますか?

22
name_masked

Java配列型のequalsメソッドは==と同等です。なぜなら、Java配列の「クラス」はObject.equalsをオーバーライドしないからです。

配列を「値で」比較する場合は、適切なJava.util.Arrays.equals(...)メソッドを使用するか、自分で実装する必要があります。

HashMapが配列をキーまたは値として使用する場合、配列のequalsメソッドを呼び出して、2つのマップ間でキーや値が同じかどうかをテストします。これにより、HashMap.equalsの動作がおかしくなります(あなたの観点から)。それはリンクされた記事が言っていることです。ただし、配列セマンティックonlyは、配列をキーまたは値クラスとして使用する場合、HashMapの等価性に影響します。そうしない場合、HashMap::equalsは期待どおりに動作するはずです。

Mapクラスの同等性に関するjavadocは少し複雑ですが、基本的には2つのエントリセットを取得し、サイズを比較してからs1.containsAll(s2)を実行することになります。もちろん、これは高価ですが、shouldMapインターフェイスを正しく実装するすべてのMapクラスで機能します。


配列をマップのキーとして使用することは、いくつかの理由で悪い考えであることに注意してください。

  1. 配列equalsおよびhashCodeのセマンティクスは、ほとんどのシナリオでHashMapに対して間違っています。ほとんどのユースケースでは、オブジェクトIDではなく値でキーを比較するマップが必要です。
  2. 配列は可変です。 equals/hashcode問題の回避策があると仮定した場合、still配列キーを変更してマップの不変式を破ることができます。
31
Stephen C

記事は正しいです。キーオブジェクトと値オブジェクトが同じメソッドを使用して比較できる限り、equals()メソッドを使用してハッシュマップを安全に比較できます。この記事では、マップ値は配列であり、期待どおりにequals()を実装していません。代わりにArrayListを使用すると、問題は解決します。

10
Eyal Schneider

ネイティブJava配列には.equals()関数がありません。したがって、ハッシュマップの値(またはキーと思われるキー)が配列の場合、HashMap.equals()は失敗します。 Object.equals()にフォールバックし、2つのオブジェクトが実際に同じオブジェクトであるかどうかを確認するだけです。

_// something like this
class Object {
  public boolean equals( Object o) {
    return this == o;
  }
}
_

コンテナには、同じ参照であるかどうかを単にチェックするのではなく、コンテナの連続する要素でequals()を呼び出す独自の.equals()があるため、array []ではなくContainerでバリアントを使用することで問題を回避できます。 。 Collection.equals実装のコードは次のようになります。

_public boolean equals(Object o) {
  // sets never equal lists and visa versa
  if (o instanceof MyCollectionSubclass) {
    Iterator myIterator = iterator();
    Iterator theirIterator = ((Collection)o).iterator();
    while (myIterator.hasNext() && theirIterator.hasNext()) {
      Object myObj = myIterator.next();
      Object theirObj = theirIterator.next();
      if (!myObj.equals(theirObj)) {
        return false;
      }
    }
    // at least one will be false or we wouldn't have left the above while loop
    return myIterator.hasNext() == theirIterator.hasNext();
  }
  // not our class
  return false;
}
_

これにより、equals()を呼び出したときにコレクションのコンテンツが何をするかに応じて、真の値の比較が生成される場合があります。

4
Mark Storer

Javaの配列は、カスタマイズされたコードを記述せずに同等性をテストできません

これはJava配列がObject.equals()をオーバーライドしないことを示す複雑な方法です。したがって、equals()(これはequalsすべてのコレクションクラスのメソッドが実行します)、「値の等価性」ではなく「インスタンスの等価性」を取得します。

これは、オーバーライドされているかどうかに応じて、equalsが機能するさまざまな方法の特別なケースです。

2
sleske