HashSet底层基于HashMap实现,元素作为key存储,value统一为PRESENT;唯一性依赖equals()和hashCode()协同,二者须同时重写;支持单个null;遍历顺序不保证。
HashSet底层用HashMap存储,key存元素、value固定用PRESENT
HashSet本身不直接管理元素去重,它内部持有一个HashMap实例,所有添加的元素都作为HashMap的key插入。而HashMap的key天然不允许重复——这正是HashSet实现唯一性的根本机制。它的value统一使用一个静态的Object对象PRESENT(仅占位,无业务意义)。
所以当你调用set.add("a"),实际执行的是map.put("a", PRESENT);第二次再add相同元素时,put会返回旧value(即PRESENT),但key没变,因此size不变,也不抛异常。
元素唯一性依赖equals()和hashCode()协同工作
仅仅重写hashCode()或equals()中的一个,会导致HashSet行为异常。必须同时满足:
- 两个逻辑上相等的对象(
a.equals(b) == true),必须返回相同的hashCode() - 如果
hashCode()不同,equals()一定不能返回true(这是HashMap桶定位的前提) - 若只重写
hashCode()而忽略equals(),可能把不同对象散列到同一桶,但因equals()返回false,仍会被视为不同元素 - 若只重写
equals()而hashCode()沿用Object默认实现(基于内存地址),那即使内容相同,哈希值也不同,它们会被分配到不同桶中,HashSet永远无法识别重复
添加null元素是合法的,且只能存在一个
HashSet允许存一个null值,因为HashMap支持key为null。其内部对null做了特殊处理:在put时,若key为null,直接放入table[0]位置,并用单独的逻辑判断是否已存在(避免调用null.hashCode())。
立即学习“Java免费学习笔记(深入)”;