Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/386.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:比较HashMap<;字符串,对象>;如果值可能是对象[]_Java_Arrays_Equals - Fatal编程技术网

Java:比较HashMap<;字符串,对象>;如果值可能是对象[]

Java:比较HashMap<;字符串,对象>;如果值可能是对象[],java,arrays,equals,Java,Arrays,Equals,我有以下带有属性键和值的HashMap: private HashMap<String, Object> prop_values; 在我得到Object[]作为一个值之前,这一直有效。因此,我以前的表达式总是在这样的HashMap上返回false,并带有任何Object[]值 因此,我必须实现这个方法: private boolean isPropValuesEquals(HashMap<String, Object> pv1, HashMap<String, O

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

private HashMap<String, Object> prop_values;
在我得到
Object[]
作为一个值之前,这一直有效。因此,我以前的表达式总是在这样的
HashMap
上返回
false
,并带有任何
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;

}
私有布尔值isPropValuesEquals(HashMap pv1,HashMap pv2){
布尔等质量=真;
if(pv1==null | | pv2==null){
返回false;
}
如果(!pv1.keySet().equals(pv2.keySet())){
返回false;
}
for(字符串键:pv1.keySet()){
对象cur_pv1=pv1.get(键);
对象cur_pv2=pv2.get(键);
if(对象[]的cur_pv1 instanceof){
if(对象[]的cur_pv2 instanceof){
isEquals=数组。等于((对象[])cur_pv1,(对象[])cur_pv2);
}否则{
返回false;
}
}否则{
isEquals=isEquals&&cur_pv1.等于(cur_pv2);
}
如果(!相等){
返回false;
}
}
返回相等;
}
它是有效的,但似乎是某种黑客行为,我不确定这是实现我所需要的最好的方式

所以,这里有两个问题:

  • 为什么对象[].equals()与数组.equals()不同?这似乎很痛苦

  • 如果值可以是
    对象[]
    ,是否有更好的方法比较
    HashMap


相等可以是不同的东西:它是同一个引用(引用相等)吗?还是有相同的内容


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

深层次的问题是无法重写数组的
equals()
。首先,我不知道为什么它不是写为“相同顺序的相等元素”。它肯定是可以的(除非有一些模糊的理由不这样做;我想不出任何理由;如果你想检查引用的相等性,你可以使用
==
,那么一个工作的
equals()
会有什么害处呢?)

你的解决方案就是出路。只需考虑几个细节:

  • 您可以使用
    x.getClass().isArray()
    ,而不是
    x instanceof Object[]
    ,这样它也可以用于其他数组,例如
    int[]
    (它不是
    Object[]
    的子类)。缺点:您可能需要单独检查
    x
    是否为
    null

  • 如果数组可能包含嵌套数组,请考虑使用<代码>数组.DeByQualSQL()/代码> .< /P> 。
基本数组不是
Object[]
s的演示:

    Object a = new int[1];
    System.out.println("" + (a instanceof Object[])); // false
    System.out.println("" + a.getClass().isArray()); // true
还有一个问题是,即使您发现
x
是一个数组,您仍然必须分别处理所有不同基本元素类型的情况。在Java的类型系统中,无法以通用方式处理它们。当然,如果在我们的映射中没有基元数组,那么就不需要处理这种情况

why Object[].equals() is not the same as Arrays.equals()?
  • Object1.equals(Object2)
    Object1==Object2
    相同,即。 比较对象的地址(许多开发人员并不期望这样,但不幸的是这是事实)
  • equals(array1,array2)比较数组的内容
关于第一点:
这是最抽象的
equals()
方法,与所有类从Object扩展的方式相同
String.equals(String)
是该方法的重写情况,它的工作方式类似于
Arrays.equals(array1,array2)
。通过这样做,他们为其他开发人员铺平了道路,让他们可以出于最灵活的目的重写它


最好使用
List
而不是
Object[]
,因为它已经准备好了所有的方法,可以满足所有的目的。

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

一个不错但效率低下的实现是

  • 复制地图
  • 用包装列表替换任何数组
  • 使用standard.equals()进行比较,这将起作用,因为列表包装器将在基础数组上执行适当的深度相等
代码


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;
}
private静态布尔值isPropValuesEquals(映射pv1,映射pv2){
如果(pv1==null | | pv2==null | | pv1.size()!=pv2.size())
返回false;
对于(Map.Entry:pv1.entrySet()){
对象cur_pv1=entry.getValue();
对象cur_pv2=pv2.get(entry.getKey());
if(cur_pv1==null^cur_pv2==null)//如果正好有一个为null,则它们“不相等”
返回false;
如果(cur_pv1!=null){
if(cur_pv1.getClass().isArray()){
if(Arrays.deepEquals((对象[])cur_pv1,(对象[])cur_pv2))
返回false;
}否则{
如果(!cur_pv1.等于(cur_pv2)){
返回false;
}
}
}
}
返回true;
}

使用一个列表而不是一个对象[],一切都会按照您的预期工作。@JBNizet,当从
对象
强制转换为参数化类型(如
列表
)时,类型安全警告会带来另一种痛苦。您会收到警告,但不会比
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
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;
}