我有一个集合,其中添加了两个不同的对象。插入后,我更改其中一个对象,使两个对象相等(通过对象类中重写的 equals 方法进行验证)。此时,我的集合中有两个重复的元素。现在我尝试将这两个重复的对象添加到一个新集合中,即使 equals 方法为它们返回 true,我仍然能够添加它们。下面是相同的代码。有人可以告诉我我到底错过了什么吗?
public class BasicSetImpl{
public int num; String entry;
public BasicSetImpl(int num, String entry){
this.num = num;
this.entry = entry;
}
@Override
public int hashCode() {
return Objects.hash(entry, num);
}
@Override
public boolean equals(Object obj) {
BasicSetImpl newObj = (BasicSetImpl)obj;
if (this.num == newObj.num)
return true;
else
return false;
}
public static void main(String[] args){
Set<BasicSetImpl> set = new HashSet<>();
BasicSetImpl k1 = new BasicSetImpl(1, "One");
BasicSetImpl k2 = new BasicSetImpl(2, "Two");
set.add(k1);
set.add(k2);
k2.num = 1;
System.out.println(k1.equals(k2)); //This line returns True
Set<BasicSetImpl> newSet = new HashSet<>();
newSet.add(k1);
newSet.add(k2);
//Set.size here is two
基于哈希的集合,在本例中,
HashSet
使用对象hashCode
方法来计算哈希值作为对象内容的函数。由于您同时考虑entry和num来确定对象的哈希码值,因此这两个对象具有不同的哈希码,因为它们与entry不同。因此,它们属于两个不同的哈希桶,并且永远不会被识别为相同。
但是,如果您按如下方式设置条目
k2.entry = "One";
那么 k1 和 k2 都有相同的 hashcode 值。那么它们都属于同一个哈希桶,并且根据 equals 方法,两个对象是相同的。因此,现在重复项将被忽略。
但是,这里潜伏着一个问题。理想情况下,相等的对象必须具有相等的哈希码。但是,就你而言,事实并非如此。如果两个对象具有相同的 num 值,则它们相等,但它们可能会产生不同的 hashcode 值。因此,正确的解决方案是按如下方式更改您的 hashCode。
@Override
public int hashCode() {
return Integer.hashCode(num);
}
现在,如果没有我们通过设置
k2.entry = "One";
添加的 hack,它应该按照您期望的方式运行
hashCode
和equals
方法必须一致。
来自文档
如果根据 equals(Object) 方法两个对象相等,则对这两个对象调用 hashCode 方法必须产生相同的整数结果。
在你的情况下,尽管它们是相等的,但他们的
hashCode
是不同的。
添加元素时HashSet
检查添加对象的哈希值,并且仅当集合中存在具有相同哈希值的现有对象时,HashSet
检查这些具有相同哈希值的对象是否相等。
套餐A;
导入java.util.HashSet; 导入 java.util.Objects;
公共班级名称{
public static class Student {
public String getNane() {
return nane;
}
public Student(String nane, int id) {
this.nane = nane;
this.id = id;
}
public void setNane(String nane) {
this.nane = nane;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String nane;
public int id;
@Override
public String toString()
{
return nane + " " + id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return id == student.id;
}
@Override
public int hashCode() {
return Objects.hash(id);
}
}
public static void main(String args[])
{
HashSet<Student> studentSet = new HashSet<>();
Student st1 = new Student("Nimit", 1);
Student st2 = new Student("Rahul", 3);
Student st3 = new Student("Nimit", 2);
Student st4 = new Student("Raj", 2);
studentSet.add(st1);
studentSet.add(st2);
studentSet.add(st3);
studentSet.add(st4);
System.out.println(studentSet.size()); // 3
st1.id = 3;
st1.nane= "Rahul";
System.out.println(studentSet.size()); // 3
studentSet.add(st1);
studentSet.forEach(System.out::println);
}
}
答案是:
3 3 拉胡尔 3 尼米特2号 拉胡尔 3
这个集合如何包含2个相同的Student对象(它们通过重写 equal 方法相等)。知道这是怎么回事吗?