8

プロパティキーと値を持つ次のHashMapがあります。

private HashMap<String, Object> prop_values;

そのインスタンスの1つが別のインスタンスと等しいかどうかを確認する必要があります。過去に、私はこれをしました:

if (prop_values_1.equals(prop_values_2)){
   //  do something
}

そして、これは私がObject[]価値として得るまで機能しました。したがって、私の前の式は常に任意の値falseでそのようなものを返しました。HashMapObject[]

だから、私はこのメソッドを実装する必要があります:

private boolean isPropValuesEquals(HashMap<String, Object> pv1, HashMap<String, Object> pv2){
   boolean isEquals = true;

   if (pv1 == null || pv2 == null){
      return false;
   }

   if (!pv1.keySet().equals(pv2.keySet())){
      return false;
   }

   for (String key : pv1.keySet()){

      Object cur_pv1 = pv1.get(key);
      Object cur_pv2 = pv2.get(key);

      if (cur_pv1 instanceof Object[]){
         if (cur_pv2 instanceof Object[]){
            isEquals = Arrays.equals((Object[])cur_pv1, (Object[])cur_pv2);
         } else {
            return false;
         }
      } else {
         isEquals = isEquals && cur_pv1.equals(cur_pv2);
      }

      if (!isEquals){
         return false;
      }
   }

   return isEquals;

}

それは機能しますが、それはある種のハックのようであり、これが私が必要とするものを達成するための最良の方法であるかどうかはわかりません。

したがって、ここに2つの質問があります。

  • Object []。equals()がArrays.equals()と同じではないのはなぜですか?痛そうです。

  • HashMap<String, Object>値が?である可能性がある場合、比較するためのより良い方法はありObject[]ますか?

4

6 に答える 6

3

equals()深刻な問題は、配列のをオーバーライドする方法がないことです。そもそもなぜ「同じ順序の等しい要素」と書かれていないのか、私にはわかりません。それは間違いなく可能でした(それを行わない理由がはっきりしない場合を除いて、私は何も考えられません。参照の同等性をチェックしたい場合は、を使用します==。それで、作業 equals()に害はありますか?)。

あなたの解決策は進むべき道です。考慮すべき詳細のほんの2、3:

  • の代わりにx instanceof Object[]、を使用できるため、(のサブクラスではないx.getClass().isArray())などの他の配列でも機能します。欠点:であるかどうかを個別に確認する必要がある場合があります。int[]Object[]xnull

  • 配列にネストされた配列が含まれている可能性がある場合は、の使用を検討してArrays.deepEquals()ください。

プリミティブ配列がsではないことのデモンストレーションObject[]

    Object a = new int[1];
    System.out.println("" + (a instanceof Object[])); // false
    System.out.println("" + a.getClass().isArray()); // true

お尻のさらに別の問題は、それxが配列であることがわかったとしても、すべての異なる原始元型のケースを個別に処理する必要があることです。Javaの型システムでは、これらを一般的な方法で処理する方法はありません。もちろん、マップにプリミティブ配列がない場合は、このケースを処理する必要はありません。

于 2012-04-19T07:56:31.960 に答える
0

平等は異なるものである可能性があります:それは同じ参照(参照の平等)ですか?それとも同じ内容ですか?

配列の問題は、配列が変更可能であるということです。equalsおよびhashCodeオブジェクトは常にペアである必要があり、ハッシュコードは変更されません(そうでない場合、オブジェクトはハッシュテーブルで見つかりません)。したがって、通常のequals(およびhashCode)は配列のコンテンツを使用できず、参照である配列の別の(変更不可能な)プロパティに依存する必要があります。

于 2012-04-19T07:50:12.420 に答える
0
why Object[].equals() is not the same as Arrays.equals()?
  • Object1.equals(Object2)と同じですObject1 == Object2。つまり、オブジェクトのアドレスを比較します(これは多くの開発者には期待されていませんが、残念ながら当てはまります)
  • Arrays.equals(array1、array2)は、配列の内容を比較します。

最初のポイント:
これはequals()メソッドの最も抽象的なものであり、すべてのクラスがObjectから拡張されるのと同じ方法です。String.equals(String)これは、そのメソッドのオーバーライドされたケースであり、Arrays.equals(array1, array2)次のように機能します。これを行うことで、他の開発者が最も柔軟な目的でメソッドをオーバーライドできるようになりました。

すべてのメソッドが用意されており、すべての目的に対応できるため、のList<Object>代わりに使用することをお勧めします。Object[]

于 2012-04-19T07:59:00.143 に答える
0

クラスObjectのequalsメソッドは、オブジェクトに対して可能な限り最も識別力のある同値関係を実装します。つまり、null以外の参照値xおよびyの場合、このメソッドは、xとyが同じオブジェクトを参照している場合にのみtrueを返します(x == yの値はtrueです)。

于 2012-04-19T07:59:08.577 に答える
0

素晴らしいが非効率的な実装は

  • 地図をコピーする
  • 配列をラップされたリストに置き換えます
  • 標準の.equals()を使用して比較を行います。これは、リストラッパーが基になる配列に対して適切なディープイコールを実行するために機能します。

コード

public static Map<String, Object> arraysToLists(Map<String, Object> map) {
    Map<String, Object> copy = new HashMap<String, Object>(map);
    for (Entry<String, Object> entry : copy.entrySet()) {
        if (entry.getValue() instanceof Object[]) {
            entry.setValue(Arrays.asList((Object[]) entry.getValue()));
        }
    }
    return copy;
}

public static boolean mapCompare(Map<String, Object> map1,
        Map<String, Object> map2) {
    return arraysToLists(map1).equals(arraysToLists(map2));
}

テストケース

public static void main(String[] args) {
    Map<String, Object> testA = new HashMap<String, Object>();
    testA.put("foo", new Object[] { "1", "2" });
    Map<String, Object> testB = new HashMap<String, Object>();
    testB.put("foo", new Object[] { "1" });
    Map<String, Object> testC = new HashMap<String, Object>();
    testC.put("foo", new Object[] { "1", "2" });

    // demonstrate equals() broken with Object arrays
    System.out.println(testA.equals(testB)); // expect false
    System.out.println(testA.equals(testC)); // expect true

    // demonstrate new function works OK
    System.out.println(mapCompare(testA, testB)); // expect false
    System.out.println(mapCompare(testA, testC)); // expect true
}

出力

false
false
false
true
于 2012-04-19T08:40:13.970 に答える
0

Joonasは正しいですが、コードを次のようにリファクタリングします。自分でチェックして違いを見つけることができます。

private static boolean isPropValuesEquals(Map<String, Object> pv1, Map<String, Object> pv2) {
    if (pv1 == null || pv2 == null || pv1.size() != pv2.size())
        return false;

    for (Map.Entry<String, Object> entry : pv1.entrySet()) {
        Object cur_pv1 = entry.getValue();
        Object cur_pv2 = pv2.get(entry.getKey());

        if (cur_pv1 == null ^ cur_pv2 == null) // if exactly one is null they're "not equal"
            return false;

        if (cur_pv1 != null) {
            if (cur_pv1.getClass().isArray()) {
                if (Arrays.deepEquals((Object[]) cur_pv1, (Object[]) cur_pv2))
                    return false;
            } else {
                if (!cur_pv1.equals(cur_pv2)) {
                    return false;
                }
            }
        }
    }

    return true;
}
于 2012-04-19T18:13:53.167 に答える