在用set接口的实现类去添加对象的时候,要求对象所属的类必须重写hashcode
和equals
方法,根据hashcode
来确定对象存储的位置,下面的一道面试题就考验了是否理解为什么要重写这两个方法
创建用于测试的person类,重写hashcode
和equals
方法
public class person {
int age;
String name;
public person(int age, String name) {
this.age = age;
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;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
int result = age;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
创建一个测试类
public class test {
public static void main(String[] args) {
HashSet set = new HashSet();
person p1 = new person(1001,"AA");
person p2 = new person(1002,"BB");
set.add(p1);
set.add(p2);
System.out.println(set);
p1.name = "CC";
set.remove(p1);
System.out.println(set);
set.add(new person(1001,"CC"));
System.out.println(set);
set.add(new person(1001,"AA"));
System.out.println(set);
}
}
看一下输出结果:
[person{age=1002, name='BB'}, person{age=1001, name='AA'}]
[person{age=1002, name='BB'}, person{age=1001, name='CC'}]
[person{age=1002, name='BB'}, person{age=1001, name='CC'}, person{age=1001, name='CC'}]
[person{age=1002, name='BB'}, person{age=1001, name='CC'}, person{age=1001, name='CC'}, person{age=1001, name='AA'}]
下面来分析每个过程
1.
第一次执行System.out.println(set);
的时候,由于new
的两个对象不同,set可以添加,并且打印成功,得到很正确的结果
[person{age=1002, name='BB'}, person{age=1001, name='AA'}]
2.
第二次执行System.out.println(set);
之前,p1.name = "CC";
改变了p1对象的属性,并且执行remove
方法,需要注意的是,这个移除并不是将p1移除,而是重新计算改变name属性后的hashcode
值,得出来的值和改变前的值是不一样的,所以并没有移除成功,原来的p1还存在,用的还是原来的hashdode值
3.
第三次执行System.out.println(set);
之前,set.add(new person(1001,"CC"));
添加了一个新的不重复对象,set添加成功,最后成功打印
4.
第四次执行System.out.println(set);
之前,由于set.add(new person(1001,"AA"));
新添加的对象和第2步中修改name后的p1有相同的hashcode值,接下来就要equals
来比交两个对象了,由于p1的name
被改为CC
,故比较后返回false
,通过链式存储在p1之后
总结
在用set接口存储数据的时候,无论是add或是remove都先需要计算该元素的hash值