Java HashSet

张开发
2026/4/20 8:35:40 15 分钟阅读

分享文章

Java HashSet
Java HashSet 学习笔记详细版一、HashSet 概述HashSet是 Java 集合框架中Set接口的一个实现类底层基于HashMap实现。它具有以下特点无序性不保证元素的存储顺序注意不是完全随机而是基于哈希值分布唯一性不允许存储重复元素允许 null 值可以存储一个null元素非线程安全多线程环境下需要手动同步或使用Collections.synchronizedSet()高性能基于哈希表增删查操作平均时间复杂度为 O(1)二、底层原理1. 基于 HashMap 实现HashSet内部维护了一个HashMap对象所有元素作为HashMap的key存储而value是一个固定的静态对象PRESENT。privatetransientHashMapE,Objectmap;// 静态常量privatestaticfinalObjectPRESENTnewObject();publicHashSet(){mapnewHashMap();}publicbooleanadd(Ee){returnmap.put(e,PRESENT)null;}2. 元素唯一性判断HashSet判断元素是否重复的逻辑调用元素的hashCode()方法计算哈希值如果哈希值不同则认为是不同元素如果哈希值相同则调用equals()方法比较内容只有当hashCode()相同且equals()返回true时才认为是重复元素⚠️重要自定义对象作为HashSet元素时必须重写hashCode()和equals()方法三、核心方法方法说明add(E e)添加元素成功返回 true重复返回 falseremove(Object o)删除指定元素contains(Object o)判断是否包含某元素size()返回元素个数isEmpty()判断是否为空clear()清空所有元素iterator()返回迭代器addAll(Collection? extends E c)批量添加元素四、使用示例1. 基本使用importjava.util.HashSet;importjava.util.Set;publicclassHashSetDemo{publicstaticvoidmain(String[]args){SetStringsetnewHashSet();// 添加元素set.add(Java);set.add(Python);set.add(Java);// 重复返回 falseset.add(C);System.out.println(set);// 输出顺序可能不同System.out.println(大小: set.size());// 3// 遍历for(Stringlang:set){System.out.println(lang);}// 判断包含System.out.println(set.contains(Python));// true// 删除set.remove(C);System.out.println(set);// [Java, Python]// 清空set.clear();System.out.println(set.isEmpty());// true}}2. 自定义对象作为元素classPerson{privateStringname;privateintage;publicPerson(Stringname,intage){this.namename;this.ageage;}// 必须重写 hashCode 和 equalsOverridepublicinthashCode(){returnname.hashCode()age;}Overridepublicbooleanequals(Objectobj){if(thisobj)returntrue;if(objnull||getClass()!obj.getClass())returnfalse;Personperson(Person)obj;returnageperson.agename.equals(person.name);}OverridepublicStringtoString(){returnPerson{namename, ageage};}}publicclassCustomObjectDemo{publicstaticvoidmain(String[]args){SetPersonpeoplenewHashSet();Personp1newPerson(张三,25);Personp2newPerson(张三,25);Personp3newPerson(李四,30);people.add(p1);people.add(p2);// 重复不会添加people.add(p3);System.out.println(people.size());// 2System.out.println(people);// [Person{name张三, age25}, Person{name李四, age30}]}}3. 批量操作SetIntegerset1newHashSet(Arrays.asList(1,2,3));SetIntegerset2newHashSet(Arrays.asList(3,4,5));// 并集SetIntegerunionnewHashSet(set1);union.addAll(set2);System.out.println(union);// [1, 2, 3, 4, 5]// 交集SetIntegerintersectionnewHashSet(set1);intersection.retainAll(set2);System.out.println(intersection);// [3]// 差集SetIntegerdifferencenewHashSet(set1);difference.removeAll(set2);System.out.println(difference);// [1, 2]五、注意事项1. 遍历顺序不确定SetIntegersetnewHashSet();for(inti0;i10;i){set.add(i);}// 输出顺序可能每次都不一样for(Integernum:set){System.out.print(num );}2. 线程安全问题// 错误示例多线程环境下可能出错SetStringsetnewHashSet();// 多个线程同时 add 可能导致数据不一致// 正确做法使用 Collections.synchronizedSetSetStringsyncSetCollections.synchronizedSet(newHashSet());// 或者使用 ConcurrentHashMap.newKeySet() (Java 8)SetStringconcurrentSetConcurrentHashMap.newKeySet();3. 性能优化初始容量设置如果知道大致元素数量可以设置初始容量避免扩容加载因子默认 0.75可根据实际情况调整// 设置初始容量为 16加载因子为 0.75SetStringsetnewHashSet(16,0.75f);六、HashSet vs TreeSet vs LinkedHashSet特性HashSetLinkedHashSetTreeSet顺序无序插入顺序自然顺序/自定义排序性能O(1)O(1)O(log n)null 支持支持支持不支持除非自定义 Comparator线程安全否否否适用场景只需唯一性需要保持插入顺序需要排序七、常见面试题1. HashSet 如何保证元素唯一性答通过hashCode()和equals()方法共同判断。先比较哈希值再比较内容。2. 为什么自定义对象要重写 hashCode 和 equals答如果不重写使用的是 Object 类的默认实现hashCode()基于内存地址equals()比较引用地址导致逻辑上相同的对象被视为不同元素。3. HashSet 和 HashMap 的关系答HashSet 底层基于 HashMap 实现元素作为 key 存储value 为固定的 PRESENT 对象。4. HashSet 是线程安全的吗答不是。多线程环境下需要使用Collections.synchronizedSet()或ConcurrentHashMap.newKeySet()。八、最佳实践始终重写 hashCode 和 equals当使用自定义对象作为元素时合理设置初始容量避免频繁扩容影响性能注意线程安全多线程环境使用同步集合或并发集合优先使用接口编程SetString set new HashSet();使用增强 for 循环或 Stream API 遍历代码更简洁// Stream API 示例SetStringsetnewHashSet(Arrays.asList(Java,Python,Java));set.stream().filter(s-s.startsWith(J)).forEach(System.out::println);九、总结HashSet是 Java 中最常用的去重集合具有以下优势✅ 高效的增删查操作O(1)✅ 自动去重✅ 使用简单✅ 支持 null 值但需要注意⚠️ 无序性⚠️ 非线程安全⚠️ 自定义对象需重写 hashCode 和 equals在实际开发中根据具体需求选择合适的 Set 实现类只需去重 →HashSet需要保持插入顺序 →LinkedHashSet需要排序 →TreeSet

更多文章