HashSet概述
HashSet实现了Set接口,该集合只能保存不重复的元素,元素保存的顺序并不按照存入时的顺序,HashSet经常用于元素去重,或者是检查数据集中是否有重复元素。
HashSet的实现
HashSet是基于HashMap实现的,HashMap是键不允许重复的,这正好契合HashSet语义,实现原理也相同,用HashMap的键集来实现HashSet就再合适不过了。
构造方法
创建HashSet内部实际上创建了一个HashMap:
public HashSet() {this.map = new HashMap();
}
添加元素
HashSet使用add()方法添加元素,添加成功返回true,添加失败返回false,添加失败就是添加的元素已存在,看看它是怎么实现的:
public boolean add(E var1) {return this.map.put(var1, PRESENT) == null;
}
添加元素实际调用了HashMap的put方法,以新增的元素作为键,PRESENT作为值,PRESENT是一个静态对象,也就是说这个内部HashMap的所有键都指向同一个值,所以不会有空间浪费,map.put(var1, PRESENT)只有键不存在时才返回空,也就代表添加成功。
删除元素
public boolean remove(Object var1) {return this.map.remove(var1) == PRESENT;
}
遍历HashSet
使用迭代器遍历:
HashSet<String> hashSet = new HashSet<>();
Iterator<String> iterator = hashSet.iterator();
while (iterator.hasNext()){iterator.next();
}
增强for循环是更方便的方式:
HashSet<String> hashSet = new HashSet<>();
for (String str : hashSet){System.out.println(str);
}
交集和差集
retainAll()方法用于求出两个集合的交集,结果保存在调用的集合内,而作为参数的集合不变:
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer> set2 = new HashSet<>(Arrays.asList(4, 5, 6, 7, 8));
//求交集
set1.retainAll(set2);
//set1 包含交集 {4, 5}
//set2 包含交集 {4, 5, 6, 7, 8}
removeAll()方法用于求出两个集合的差集:
Set<Integer> set1 = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5));
Set<Integer> set2 = new HashSet<>(Arrays.asList(4, 5, 6, 7, 8));
// 求差集
set1.removeAll(set2);
//set1 现在包含差集 {1, 2, 3}
//set2 包含交集 {4, 5, 6, 7, 8}
注意事项
- HashSet 不允许重复元素,如果试图添加重复的元素,重复元素将被忽略。
- HashSet 不保证元素的顺序,元素在 HashSet 中是无序的。
- HashSet 是非线程安全的,如果在多线程环境下使用 HashSet,需要注意线程同步,或者考虑使用线程安全的集合类,如 ConcurrentHashSet。
- HashSet允许存储一个null元素,但通常建议避免将null作为有效元素存储,以免混淆和错误。
- 在使用自定义对象作为HashSet元素时,需要正确实现 hashCode() 和 equals() 方法,以确保对象在集合中的唯一性和正确性。
- HashSet 的性能通常是很高的,但在处理大量数据时,应注意负载因子的设置,以避免频繁的扩容操作。
- 如果只是要判断元素是否重复,在数据量大时使用BitSet会更省空间。
参考
【Java 基础篇】Java HashSet 集合详解:高效存储唯一元素的利器_51CTO博客_java集合hashset用法