Set接口是Java集合框架中的一个重要接口,它表示一个不包含重复元素的集合。Set
接口继承自Collection
接口,因此它继承了Collection
接口的所有方法,并且添加了一些特定于Set
的方法。以下是对Set
接口下通用方法的详细讲解和代码示例。
一、Set接口概述
Set
接口的主要特点包括:
- 不允许存储重复元素。
- 无序(对于
HashSet
)或有序(对于TreeSet
和LinkedHashSet
)。 - 没有索引,不能通过索引访问元素,也不能通过普通for循环遍历。
常见实现类
HashSet
:基于哈希表实现,无序且不允许重复元素。LinkedHashSet
:基于哈希表和链表实现,保持插入顺序且不允许重复元素。TreeSet
:基于红黑树实现,元素按自然顺序或指定比较器排序且不允许重复元素。
二.核心方法概览
方法签名 | 作用 | 返回值说明 |
---|---|---|
boolean add(E e) |
添加元素(若元素已存在则忽略) | 成功添加返回true ,否则false |
boolean addAll(Collection<? extends E> c) |
添加另一个集合的所有元素 | 集合有变化返回true |
boolean remove(Object o) |
删除指定元素 | 存在并删除返回true |
void clear() |
清空集合 | - |
int size() |
返回元素数量 | 空集合返回0 |
boolean isEmpty() |
判断集合是否为空 | 空集合返回true |
boolean contains(Object o) |
判断是否包含元素 | 存在返回true |
boolean containsAll(Collection<?> c) |
判断是否包含另一个集合的所有元素 | 全包含返回true |
Iterator<E> iterator() |
返回迭代器 | 用于遍历集合 |
Object[] toArray() |
将集合转为数组 | 返回Object[] |
<T> T[] toArray(T[] a) |
将集合转为指定类型的数组 | 返回类型化数组 |
1. 添加元素
add(E e)
:将指定元素添加到此集合中(如果尚未存在)。addAll(Collection<? extends E> c)
:将指定集合中的所有元素添加到此集合中(如果尚未存在)。
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");
System.out.println(set); // 输出:[Apple, Banana, Cherry]
Set<String> moreFruits = new HashSet<>();
moreFruits.add("Date");
moreFruits.add("Elderberry");
set.addAll(moreFruits);
System.out.println(set); // 输出:[Apple, Banana, Cherry, Date, Elderberry]
}
}
2. 删除元素
remove(Object o)
:从此集合中移除指定元素(如果存在)。removeAll(Collection<?> c)
:从此集合中移除指定集合中包含的所有元素。clear()
:从此集合中移除所有元素。
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");
System.out.println(set); // 输出:[Apple, Banana, Cherry]
set.remove("Banana");
System.out.println(set); // 输出:[Apple, Cherry]
Set<String> fruitsToRemove = new HashSet<>();
fruitsToRemove.add("Apple");
fruitsToRemove.add("Cherry");
set.removeAll(fruitsToRemove);
System.out.println(set); // 输出:[]
set.add("Date");
set.add("Elderberry");
set.clear();
System.out.println(set); // 输出:[]
}
}
3. 检查元素
contains(Object o)
:如果此集合包含指定元素,则返回true
。containsAll(Collection<?> c)
:如果此集合包含指定集合中的所有元素,则返回true
。isEmpty()
:如果此集合不包含任何元素,则返回true
。
import java.util.HashSet;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");
System.out.println(set.contains("Apple")); // 输出:true
System.out.println(set.contains("Grape")); // 输出:false
Set<String> fruitsToCheck = new HashSet<>();
fruitsToCheck.add("Apple");
fruitsToCheck.add("Banana");
System.out.println(set.containsAll(fruitsToCheck)); // 输出:true
System.out.println(set.isEmpty()); // 输出:false
}
}
4. 集合操作
size()
:返回此集合中的元素数量。iterator()
:返回在此集合的元素上进行迭代的迭代器。toArray()
:返回包含此集合中所有元素的数组。retainAll(Collection<?> c)
:仅保留此集合与指定集合的交集。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");
System.out.println(set.size()); // 输出:3
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println(); // 输出:Apple Banana Cherry
Object[] array = set.toArray();
for (Object obj : array) {
System.out.print(obj + " ");
}
System.out.println(); // 输出:Apple Banana Cherry
Set<String> fruitsToRetain = new HashSet<>();
fruitsToRetain.add("Apple");
fruitsToRetain.add("Banana");
set.retainAll(fruitsToRetain);
System.out.println(set); // 输出:[Apple, Banana]
}
}
三.Set接口对象的遍历
// 方法1:迭代器
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
// 方法2:增强for循环
for (String s : set) {
System.out.println(s);
}
// 方法3:Java 8 forEach
set.forEach(System.out::println);
四.各个实现类之间的不同点
1.HashSet - 基于哈希表的快速集合
底层实现:
- 基于
HashMap
实现 - 元素存储为
HashMap
的 key - Value 使用固定的
PRESENT
对象填充
特殊点
- 不允许重复元素:当向
HashSet
中添加重复元素时,新元素不会被添加进去,因为HashSet
会根据元素的hashCode()
和equals()
方法来判断元素是否重复。 - 允许存储
null
元素:HashSet
最多可以存储一个null
元素。 - 性能较高:添加、删除和查找元素的时间复杂度接近 O(1),因为它是基于哈希表实现的。
import java.util.HashSet;
import java.util.Set;
public class HashSetExample {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("apple"); // 重复元素,不会被添加
set.add(null); // 允许存储 null 元素
for (String element : set) {
System.out.println(element);
}
}
}
2.LinkedHashSet
底层实现:
- 继承
HashSet
- 内部使用
LinkedHashMap
实现 - 维护元素插入顺序的双向链表
特殊点
- 保持插入顺序:
LinkedHashSet
会记录元素插入的顺序,因此遍历元素时会按照插入的顺序输出。 - 性能稍低于
HashSet
:由于需要维护链表来记录插入顺序,LinkedHashSet
的性能比HashSet
略低,但仍然具有较好的性能。 - 允许存储
null
元素:和HashSet
一样,LinkedHashSet
最多可以存储一个null
元素。
import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetExample {
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<>();
set.add("apple");
set.add("banana");
set.add("cherry");
for (String element : set) {
System.out.println(element); // 按插入顺序输出
}
}
}
3.TreeSet
TreeSet 是一个基于红黑树(自平衡二叉搜索树)实现的有序集合。TreeSet
中的元素会根据自然顺序或者指定的比较器进行排序。
特殊点
- 元素有序:
TreeSet
中的元素会按照自然顺序(如果元素实现了Comparable
接口)或者指定的比较器(通过构造函数传入Comparator
对象)进行排序。 - 不允许存储
null
元素:因为TreeSet
需要对元素进行比较排序,而null
无法进行比较,所以不允许存储null
元素。 - 性能为 O(logn):插入、删除和查找元素的时间复杂度为 O(logn),因为它是基于红黑树实现的。
import java.util.TreeSet;
import java.util.Set;
public class TreeSetExample {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<>();
set.add(3);
set.add(1);
set.add(2);
for (Integer element : set) {
System.out.println(element); // 按升序输出
}
}
}