题目
public class TestPerson {
public static void main(String[] args) {
HashSet<Person> set = new HashSet<>();
Person p1 = new Person(1001, "AAA");
Person p2 = new Person(1002, "BBB");
set.add(p1);
set.add(p2);
p1.name = "CCC";
set.remove(p1);
System.out.println(set);
set.add(new Person(1001,"CC"));
System.out.println(set);
set.add(new Person(1001,"AAA"));
System.out.println(set);
}
}
其中Person类重写了hashCode、equals、和toString方法
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;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
问输出结果是多少?
分析
答题前我们首先要知道:
JDK1.8后,HashSet和HashMap存储结构都是哈希表(由数组+链表+红黑树实现)。
HashSet和HashMap存储过程:
1.根据key的hash值计算位置,如果这个位置没有元素,则直接添加。
2.如果这个位置有元素,再比较hash值,如果hash值不同,则形成链表。
3.如果hash值相同,再比较equals方法,如果equals方法为false,则形成链表,如果为true,则认为是重复元素,不再添加。
位置相同,hash值相同,equals为true同时成立才认为是重复元素。
HashSet和HashMap删除过程:
同理要位置相同,hash值相同,equals为true同时成立才认为是重复元素,才能删除。
回到题目
set.add(p1)、set.add(p2): set首先添加p1(1001,“AAA”)、p2(1002,“BBB”)对象后,将p1对象的name值改变了(1001,“CCC”),此时虽然set中p1的属性值为(1001,“CCC”),但其数组位置是按照(1001,“AAA”)计算的。
set.remove(p1): 此时位置是按照更改后的(1000,“CCC”)计算的,与set中存储的p1的位置不同,故认为set中没有与之重复的元素,不删除。
set.add(new Person(1001,“CC”)): 理由同上,此时按照更改后的属性计算的位置与原本计算的位置不同,故认为set中没有与之重复的元素,于是将其添加进数组。
set.add(new Person(1001,“AAA”)): 属性与p1原属性相同,按照此属性计算的位置与p1在数组中存储的位置相同,于是再比较hash值,hash值不同(重写了hashCode函数,属性相同hash相同,属性不同hash不同。当然,不重写hashCode函数两者hash值也不同)。故认为两者不是重复元素,将新对象添加再p1后形成链表。
综上,这道题最后的答案是:
hashCode()方法和equal()方法的作用其实一样,在Java里都是用来对比两个对象是否相等一致,那么equal()既然已经能实现对比的功能了,为什么还要hashCode()呢?
答:因为重写的equal()里一般比较的比较全面比较复杂,这样效率就比较低,而利用hashCode()进行对比,则只要生成一个hash值进行比较就可以了,效率很高。
hashCode()既然效率这么高为什么还要equal()呢?
答:因为hashCode()并不是完全可靠,有时候不同的对象他们生成的hashcode也会一样(生成hash值的公式存在的问题),所以hashCode()只能说是大部分时候可靠,并不是绝对可靠。
参考文章:https://blog.csdn.net/weixin_30229705/article/details/112441923