HashSet通过HashMap的键唯一性实现去重,将元素作为key、PRESENT作value存储;判断重复需hashCode()与equals()共同作用,自定义类须重写二者;底层调用map.put(e, PRESENT)并依据返回值是否为null判定添加成功。
HashSet本身不直接管理元素是否重复,而是把所有元素作为内部HashMap的key来存储,value统一用一个空对象(PRESENT)占位。因为HashMap规定同一个key只能存在一份,所以只要元素能被正确识别为“同一个key”,就不会重复添加。
往HashSet里add一个对象时,会按以下顺序判断:
hashCode(),算出哈希值,定位到哈希表中某个桶(数组位置)equals()比较——只有当hashCode()相同 且 equals()返回true,才认定是重复元素,跳过添加注意:自定义类(比如Student)若想在HashSet中正确去重,必须同时重写hashCode()和equals(),否则默认按内存地址比较,两个内容相同的对象也会被当成不同元素。
看源码就能确认这一点:
HashSet.add(e) 内部调用的是 map.put(e, PRESENT)
HashMap.put()在发现key已存在时,会用新value覆盖旧value,并返回旧value;如果key不存在,则返回nullput(...) == null 来判断是否真正新增成功这些不是去重机制本身决定的,而是由底层HashMap行为自然带来的: