我有以下带有属性键和值的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[]
?
答案 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)
平等可以是不同的东西:它是相同的参考(参考平等)吗?或者它的内容是否相同?
数组的问题是它们是可变的。对象的equals
和hashCode
必须始终成对,并且哈希代码不应更改(否则在哈希表中找不到对象)。因此,正常equals
(和hashCode
)不能使用数组内容,它们必须依赖于数组的另一个(非可变)属性,这是引用。
答案 2 :(得分:0)
why Object[].equals() is not the same as Arrays.equals()?
Object1.equals(Object2)
与Object1 == Object2
相同,即
比较对象的地址(很多开发人员都没有这样做,但不幸的是这是真的)第一点:
这是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)
一个不错但也很低效的实现是
代码
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;
}