最近开发中review代码时发现一个bug,情况大概是这样:
1、往HashSet集合里add对象Person
2、改变Person对象某个属性
3、调用集合remove方法发现不起作用,集合元素没有减少
擦擦汗,抓紧看了下Hashset remove源码如下:
public boolean remove(Object o) {return map.remove(o)==PRESENT; }
发现Hashset remove方法实际调用了其成员变量HashMap的remove,继续看hashmap的remove方法
public V remove(Object key) {
Node<K,V> e;
return (e = removeNode(hash(key), key, null, false, true)) == null ?null : e.value;
}
黄色部分可以看出,hashmap在做任何操作的时候都会根据key值做hash算法,通过hash值去寻找定位key所在的index,
因此针对当前案例来看,remove方法会首先调用Person对象的hashcode()方法计算hash值,再做删除操作,如果删除无效,只能证明这个hash值发生了变化,因此马上打开Person类的hashcode方法查看(简单重写):
@Override
public int hashCode() {return this.age.hashCode();}
果不其然,Person类重写了hashcode方法,hashcode和对象的属性值相关,因此在remove操作前如果有修改对象的属性值,则会导致对象的hashcode发生变更,从而导致hashset集合hash算法找不到对应的索引位置。