Set集合
Set集合中的元素是无序的(这里的无序指的是元素的放入顺序),另外Set集合中不能包含重复的元素。主要的Set集合类包括:HashSet
、TreeSet
和EnumSet
。
HashSet类
HashSet
集合利用哈希表存储数据,哈希表存储时会涉及到元素冲突问题,这里解决冲突使用的是拉链法,也就是将哈希码相同的元素放在一个链表上。在向该集合插入元素时,需要先计算元素的hashcode
确定元素的存储位置,然后在通过equals()
方法判断元素是否与已有元素重复。因此,对于需要放入Set集合中的对象需要重写同时hashCode()
和'equals()'方法。
HashSet
的特点:
- 不保证元素的排列顺序
-
HashSet
是线程不安全的 - 元素的值可以为
null
public static void testHashSet() {
HashSet<String> set = new HashSet<>();
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.remove("aaa");
set.add("aaa");
Iterator<String> it = set.iterator();
System.out.println("testHashSet: ");
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
System.out.println();
}
移除元素aaa
后再重新添加,输出次序不变,说明HashSet
元素顺序与插入顺序无关。
LinkedHashSet类
LinkedHashSet
继承了HashSet
类,同样使用哈希码决定元素的存储位置,但是它采用链表维护元素的插入次序,因此它是有序的Set
集合。其余性质与HashSet
一致。
public static void testLinkedHashSet() {
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("aaa");
linkedHashSet.add("bbb");
linkedHashSet.add("ccc");
linkedHashSet.remove("aaa");
linkedHashSet.add("aaa");
Iterator<String> it = linkedHashSet.iterator();
System.out.println("testLinkedHashSet: ");
while (it.hasNext()) {
System.out.print(it.next() + " ");
}
}
移除元素aaa
后再重新添加,aaa
最后输出,说明LinkedHashSet
维护了元素的插入次序。
TreeSet类
TreeSet
是SortedSet
接口的实现类,该集合中的元素是按照元素的大小来排序的,TreeSet
采用红黑树的数据结构来存储集合中的元素,不允许插入null
。对于元素的大小判定可以按照自然排序也可以采用自定义的排序规则。
public static void testTreeSet() {
TreeSet treeSet = new TreeSet();
treeSet.add(7);
treeSet.add(1);
treeSet.add(-4);
treeSet.add(19);
treeSet.add(12);
for (Object num : treeSet) {
System.out.println(num);
}
}
EnumSet类
EnumSet
是专为枚举类设计的集合类,EnumSet
集合中的元素必须是指定的枚举类中的值,EnumSet
集合中元素的存储顺序与相应的枚举类中的元素顺序一致,不允许包含null
值。
总结
通常情况下,只有希望集合中的元素有序(不是指插入顺序)时才考虑使用
TreeSet
毕竟维护红黑树结构需要一定的开销,另外根据对集合的常用操作来选择使用HashSet
还是LinkedHashSet
,如果需要对集合经常插入和删除则采用HashSet
,因为LinkedHashSet
需要维护一个链表,也因此LinkedHashSet
的遍历更快。- 虽然
EnumSet
是所有Set
中性能最好的,但是由于它只能用于存储枚举类中的元素,限制了它的使用场景。 这里所有的
Set
类都是线程不安全的。