Java:比较HashMap <string,object =“”>如果value可能是Object [] </string,>

时间:2012-04-19 07:42:15

标签: java arrays equals

我有以下带有属性键和值的HashMap:

private HashMap<String, Object> prop_values;

我需要检查它的一个实例是否等于另一个实例。在过去,我刚刚这样做了:

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

这一直有效,直到我得到Object[]作为值。因此,我之前的表达式总是在false上返回HashMap,其值为Object[]

所以,我必须实现这个方法:

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;

}

它有效,但它似乎是某种黑客,我不确定这是实现我需要的最佳方式。

所以,这里有两个问题:

  • 为什么Object []。equals()与Arrays.equals()不一样?这似乎很痛苦。

  • 是否有更好的方法来比较HashMap<String, Object>,如果值可以是Object[]

6 个答案:

答案 0 :(得分:3)

深层问题是没有办法覆盖数组的equals()。为什么它不是首先写成“相同顺序的相同元素”,我不知道。它绝对可能是(除非有一些不明智的理由不做;我想不出任何;如果你想检查引用相等,你使用==,那么工作{{1}伤害?)。

您的解决方案是可行的方法。只需要考虑几个细节:

  • 您可以使用equals()代替x instanceof Object[],因此它也适用于其他数组,例如x.getClass().isArray() int[]的子类。缺点:您可能需要单独检查Object[]x

  • 如果数组可能包含嵌套数组,请考虑使用null

原始数组不是Arrays.deepEquals() s:

的演示
Object[]

屁股的另一个痛苦是,即使你发现 Object a = new int[1]; System.out.println("" + (a instanceof Object[])); // false System.out.println("" + a.getClass().isArray()); // true 是一个数组,你仍然需要处理所有不同原始元素类型的单独案例。在Java的类型系统中,没有办法以通用的方式处理它们。当然,如果你的地图中没有原始数组,那么你不需要处理这种情况。

答案 1 :(得分:0)

平等可以是不同的东西:它是相同的参考(参考平等)吗?或者它的内容是否相同?

数组的问题是它们是可变的。对象的equalshashCode必须始终成对,并且哈希代码不应更改(否则在哈希表中找不到对象)。因此,正常equals(和hashCode)不能使用数组内容,它们必须依赖于数组的另一个(非可变)属性,这是引用。

答案 2 :(得分: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[],因为它已准备好所有方法并且可以满足所有目的。

答案 3 :(得分:0)

类Object的equals方法实现了对象上最具辨别力的等价关系;也就是说,对于任何非空引用值x和y,当且仅当x和y引用同一对象时,此方法才返回true(x == y的值为true)。

答案 4 :(得分: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

答案 5 :(得分: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;
}