Set和Map的核心共性是不允许重复key/元素,但语义不同:Set禁重复元素,Map禁重复key(value可重复);均依赖equals()和hashCode()判重(TreeSet/TreeMap例外,用Comparable/Comparator但要求与equals一致);HashSet底层基于HashMap实现,add(e)即map.put(e, PRESENT);默认不保证顺序,需有序用LinkedHashSet/LinkedHashMap或TreeSet/TreeMap;并发集合如ConcurrentHashMap也不保证顺序;二者均非直接实现接口,而是继承AbstractSet/AbstractMap复用逻辑;null容忍度不统一:HashSet和HashMap允许一个null,TreeSet/TreeMap未指定Comparator时插入null抛NPE。

Set 和 Map 都不允许重复的 key / 元素
这是最核心的共性,但要注意语义差异:Set 不允许重复元素,Map 不允许重复 key(value 可重复)。底层都依赖 equals() 和 hashCode() 判断“重复”——如果两个对象 equals() 返回 true,它们必须有相同的 hashCode(),否则 HashSet 或 HashMap 会失效。
- 没重写
equals()和hashCode()的自定义类,放进HashSet或作为HashMap的key时,几乎必然出现“逻辑重复却未去重”的问题 -
TreeSet和TreeMap是例外:它们不依赖hashCode(),而是用Comparable或Comparator比较大小,但依然要求比较结果与equals()一致(即:若a.compareTo(b) == 0,则a.equals(b)必须为true)
底层实现高度耦合,HashMap 是 HashSet 的实际支撑
HashSet 内部直接持有一个 HashMap 实例,只是把所有元素当作 key 存入,value 固定用一个私有静态对象 PRESENT 占位。这意味着:
-
HashSet的性能、扩容机制、线程安全性(或缺乏)完全继承自其内部的HashMap - 调用
HashSet.add(e)实际执行的是map.put(e, PRESENT) - 所以
HashSet的初始容量、负载因子等参数,本质就是配置它背后那个HashMap
都不保证迭代顺序(除非使用特定子类)
默认的 HashSet 和 HashMap 均不保证插入或遍历顺序,因为基于哈希表实现,顺序取决于 hashCode() 和当前桶数组状态。
产品介绍微趣能 Weiqn 开源免费的微信公共账号接口系统。MVC框架框架结构清晰、易维护、模块化、扩展性好,性能稳定强大核心-梦有多大核心就有多大,轻松应对各种场景!微趣能系统 以关键字应答为中心 与内容素材库 文本 如图片 语音 视频和应用各类信息整体汇集并且与第三方应用完美结合,强大的前后台管理;人性化的界面设计。开放API接口-灵活多动的API,万名开发者召集中。Weiqn 系统开发者AP
- 需要插入顺序 → 改用
LinkedHashSet或LinkedHashMap - 需要自然排序 → 改用
TreeSet或TreeMap -
ConcurrentHashMap和CopyOnWriteArraySet这类并发集合,同样不保证顺序,且迭代器行为更特殊(可能反映某一时刻快照,而非实时状态)
都不是接口的直接实现者,而是靠抽象类或组合封装
Set 和 Map 都是接口,但常见实现并非从头写起:
立即学习“Java免费学习笔记(深入)”;
-
AbstractSet提供了equals()、hashCode()、removeAll()等默认实现,HashSet继承自AbstractSet -
AbstractMap封装了entrySet()、keySet()、values()等通用逻辑,HashMap继承自AbstractMap - 这种设计让新增集合实现(如自定义缓存容器)可以复用大量基础行为,但也意味着:直接继承
AbstractSet却忘了重写iterator(),会导致NullPointerException
public class MySet真正容易被忽略的是:**extends AbstractSet { private final List list = new ArrayList<>(); @Override public Iterator iterator() { return list.iterator(); // 必须重写!否则 super.iterator() 抛 NPE } @Override public int size() { return list.size(); } }
Set 和 Map 对 null 的容忍度并不统一**。HashSet 允许一个 null 元素,HashMap 允许一个 null key;但 TreeSet 和 TreeMap 在未指定 Comparator 时,直接放入 null 会抛 NullPointerException——这个差异不是设计疏漏,而是由比较逻辑决定的。









