今天遇到一件怪事,用一个ArrayList添加了一个对象,再调用ArrayList的remove方法删除该对象,当然这时对象是数据库里查出来的,但内容绝对是一样,却发现remove失败了。演示一下,这里用了自定义的Merchant对象,测试时只需随便自定义一个对象即可:
public static void main(String[] args) { List<Merchant> merchants = new ArrayList<>(); Merchant merchant = new Merchant(); merchant.setMerchantId("aa"); merchant.setMarketPlaceId("bb"); merchant.setSecretKey("aa"); merchant.setAccessKeyId("bb"); merchants.add(merchant); Merchant other = new Merchant(); other.setMerchantId("aa"); other.setMarketPlaceId("bb"); other.setSecretKey("aa"); other.setAccessKeyId("bb"); boolean isRemoved = merchants.remove(other); System.out.println(isRemoved); }
结果打印出来是false。然后去看了一下ArrayList的remove方法:
public boolean remove(Object var1) { int var2; if (var1 == null) { for(var2 = 0; var2 < this.size; ++var2) { if (this.elementData[var2] == null) { this.fastRemove(var2); return true; } } } else { for(var2 = 0; var2 < this.size; ++var2) { if (var1.equals(this.elementData[var2])) { this.fastRemove(var2); return true; } } } return false; } private void fastRemove(int var1) { ++this.modCount; int var2 = this.size - var1 - 1; if (var2 > 0) { System.arraycopy(this.elementData, var1 + 1, this.elementData, var1, var2); } this.elementData[--this.size] = null; }
关键在标黄那一行,remove的前提是两个对象的equals方法必须相等,而我定义的Merchant对象并无复写Object类的equals方法,那么执行到这一行时equals就是Object的equals方法:
public boolean equals(Object obj) { return (this == obj); }
是否一下子有种恍然大悟的被坑的感觉?反正我是这样子觉得的,Object类比较的是引用,而main里测试的是两个不同的引用,equals必然是false,remove自然也是false了,不信可以把equals也一并打印一下:
public static void main(String[] args) { List<Merchant> merchants = new ArrayList<>(); Merchant merchant = new Merchant(); merchant.setMerchantId("aa"); merchant.setMarketPlaceId("bb"); merchant.setSecretKey("aa"); merchant.setAccessKeyId("bb"); merchants.add(merchant); Merchant other = new Merchant(); other.setMerchantId("aa"); other.setMarketPlaceId("bb"); other.setSecretKey("aa"); other.setAccessKeyId("bb"); boolean isRemoved = merchants.remove(other); System.out.println(other.equals(merchant)); System.out.println(isRemoved); }
你会发现两个false出现了。那么咋办呢?很简单,既然是equals引起的,那就让它来解决问题,我们再Merchant里重写Object的equals即可。当然既然重写了equals,我们也得把hashCode方法也一起重写一下,现在的IDE都很智能,自动生成即可。等你的自定义类生成好了这俩方法后,重新执行上面这个main,你会发现出现俩true了。
当然,如果你希望在自定义的对象里修改了非关键属性(比如上面的Merchant里的accessKeyId、secretKey等这些属性,在数据库update他们的值之后就都改变了)都不影响该对象的唯一性,那么我们可以把equals和hashCode方法里自动生成的其他属性去掉,只保留能识别该对象的关键属性(比如merchantId)。
原文地址:https://www.cnblogs.com/wuxun1997/p/10887511.html