HashSet不保证元素顺序,LinkedHashSet按插入顺序维护;前者基于HashMap无序遍历,后者额外维护双向链表实现有序迭代;两者均允许null、不允许重复,判重逻辑相同,构造参数均透传至内部HashMap。

HashSet不保证元素顺序,LinkedHashSet按插入顺序维护
这是最直观的区别:HashSet底层用HashMap实现,只关心哈希值和桶位置,遍历时顺序完全不可预测;LinkedHashSet则在HashMap基础上额外维护一个双向链表,把每次add()的元素按实际插入顺序串起来。所以如果你写new LinkedHashSet(Arrays.asList("a", "b", "c")),后续遍历一定得到a → b → c;而HashSet可能输出b → a → c甚至其他排列。
LinkedHashSet内存开销略高,但迭代性能更稳定
LinkedHashSet每个元素要多存两个引用(before和after),对象头+链表指针带来约8–16字节额外开销(取决于JVM位数)。不过这对绝大多数应用影响极小。真正要注意的是迭代行为:HashSet遍历时要扫描整个哈希表数组+所有链表/红黑树节点,实际访问路径跳跃、缓存不友好;LinkedHashSet则顺着链表线性访问,CPU缓存命中率高,尤其在元素较多且频繁遍历时更平稳。
两者都允许null,但都不支持重复元素
它们都继承自AbstractSet,判重逻辑完全一致:依赖元素的hashCode()和equals()。以下行为完全相同:
-
set.add(null)—— 都只允许一个null -
set.add(new String("x"))后再次add("x")—— 都返回false,集合大小不变 - 自定义类必须正确重写
hashCode()和equals(),否则两者都会失效
别指望LinkedHashSet能靠“顺序”绕过重复检查——它只是记住谁先来,但依然严格遵循Set契约。
立即学习“Java免费学习笔记(深入)”;
构造时传入容量或负载因子,LinkedHashSet会透传给内部HashMap
LinkedHashSet所有带参数的构造方法,最终都调用HashMap对应构造器。例如:
new LinkedHashSet(16, 0.75f); // 等价于 new HashMap<>(16, 0.75f) + 链表初始化
这意味着:
- 初始容量和负载因子影响的是哈希表部分的扩容时机,和链表无关
- 如果提前知道大概元素数量,设合理初始容量可避免多次rehash,对两者都有益
-
LinkedHashSet(int initialCapacity)默认负载因子仍是0.75f,不是1.0f
顺序保障只来自链表结构,跟哈希表参数无关;但参数选得差,会导致哈希冲突增多,间接拖慢add()和contains()——这点常被忽略。










