问题
public class PatternTest {
public static void main(String[] args) {
Set<Person> set = new HashSet<>();
Person p1 = new Person(1,"张三");
set.add(p1);
Person p2 = new Person(2,"李四");
set.add(p2);
System.out.println("1:"+p1.hashCode());
p1.name = "张三三0";
System.out.println("2:"+p1.hashCode());
set.removeIf(item->{
System.out.println("3:"+item.hashCode()+" "+item.name);
return item.id == 1;
});
System.out.println(set.size());
}
}
class Person{
int id;
String name;
public Person(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return id == person.id && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
上述代码中执行remove后无法删除set中id为1的person
原因
HashSet是根据hashcode方法定位数组索引的,当修改person.name后,person的hashcode值会发生变化,即该对应在数组中的索引与之前不同了,再remove重新计算hashcode时,删除另一个索引上的链表中数据,即无法删除原对象
该问题更多的出现在 Person被标注了 @Data的情况下,lomok现在使用越来越多,在@Data标注时,会根据所有的字段重写 hashcode及equal