在Java中,Collection
接口是集合框架的根接口之一,它表示一组对象的集合。Collection
接口提供了对集合进行基本操作的方法,如添加、删除、遍历等。它定义了以下常用方法:
boolean add(E e)
:将指定的元素添加到集合中(可选操作)。boolean addAll(Collection<? extends E> c)
:将指定集合中的所有元素添加到集合中(可选操作)。void clear()
:从集合中移除所有元素(可选操作)。boolean contains(Object o)
:如果集合中包含指定的元素,则返回true。boolean containsAll(Collection<?> c)
:如果集合包含指定集合中的所有元素,则返回true。boolean isEmpty()
:如果集合不包含任何元素,则返回true。Iterator<E> iterator()
:返回在此集合上进行迭代的迭代器。boolean remove(Object o)
:从集合中移除指定的元素(可选操作)。boolean removeAll(Collection<?> c)
:从集合中移除包含在指定集合中的所有元素(可选操作)。boolean retainAll(Collection<?> c)
:仅保留集合中包含在指定集合中的元素(可选操作)。int size()
:返回集合中的元素个数。Object[] toArray()
:返回包含集合所有元素的数组。<T> T[] toArray(T[] a)
:返回包含集合所有元素的数组,并根据指定数组的运行时类型进行转换。
Collection
接口的常见实现类包括List
、Set
和Queue
等,它们分别表示有序集合、无序集合和队列。通过实现Collection
接口,可以使得各种集合类具有统一的操作方式和特性,从而更方便地进行集合操作和管理。
下面是 Java 中 Collection、List、Set 和 Map 之间的关系图:
┌──────── Collection ────────┐
│ │
│ │
┌─────────────────┴─────────┐ ┌──────────┴─────────┐
│ │ │ │
│ │ │ │
List Set Queue Map
│ │ │ │
│ │ │ │
│ │ │ │
ArrayList HashSet | PriorityQueue HashMap
LinkedList TreeSet │ LinkedList TreeMap
Vector LinkedHashSet LinkedHashMap
│
│
EnumSet
Collection
是所有集合类的根接口,它定义了集合类的通用行为和方法。List
接口表示有序集合,允许重复元素,可以根据索引位置访问元素。Set
接口表示无序集合,不允许重复元素,不支持索引访问。Queue
接口表示队列,通常按照先进先出(FIFO)的方式处理元素。Map
接口表示键值对的集合,其中每个键都是唯一的,键关联到值。
具体实现类如下:
ArrayList
、LinkedList
和Vector
实现了List
接口,分别表示动态数组、链表和向量。HashSet
、TreeSet
和LinkedHashSet
实现了Set
接口,分别表示哈希集、树集和链哈希集。PriorityQueue
实现了Queue
接口,表示优先级队列。HashMap
、TreeMap
、LinkedHashMap
实现了Map
接口,分别表示哈希映射、树映射和链哈希映射。EnumSet
是Set
接口的特殊实现,用于存储枚举类型的元素。
这些类之间的关系是通过实现接口或继承来实现的。
EnumSet
是 Java 中用于表示枚举类型元素集合的特殊类。 它是 AbstractSet
的子类,设计用来与枚举类型一起使用,提供了高效的枚举集合实现。
特点和使用方法包括:
- 只能存储枚举类型的元素:
EnumSet
只能存储同一枚举类型的元素,不能存储其他类型的对象。 - 底层使用位向量实现:
EnumSet
使用位向量(bit vector)来表示集合中的元素,因此非常高效。 - 不允许存储 null 值:
EnumSet
不允许存储 null 值,如果尝试存储 null 值会抛出NullPointerException
。 - 枚举元素顺序与枚举常量声明顺序一致:
EnumSet
中的枚举元素的迭代顺序与枚举常量声明的顺序一致。 - 不是线程安全的:
EnumSet
不是线程安全的,如果多个线程同时访问同一个EnumSet
实例,并且至少有一个线程修改了集合,那么它必须在外部进行同步。 - 性能高效:由于底层使用位向量实现,因此
EnumSet
提供了非常高效的性能。
以下是一个简单的示例,演示了如何使用 EnumSet
:
import java.util.EnumSet;
public class EnumSetExample {
enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }
public static void main(String[] args) {
// 创建一个包含所有枚举值的 EnumSet
EnumSet<Day> allDays = EnumSet.allOf(Day.class);
System.out.println("All days: " + allDays);
// 创建一个空的 EnumSet
EnumSet<Day> emptySet = EnumSet.noneOf(Day.class);
System.out.println("Empty set: " + emptySet);
// 创建一个包含指定范围的 EnumSet
EnumSet<Day> workDays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
System.out.println("Work days: " + workDays);
// 创建一个 EnumSet,排除指定的元素
EnumSet<Day> weekend = EnumSet.complementOf(workDays);
System.out.println("Weekend: " + weekend);
}
}
输出结果为:
All days: [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY]
Empty set: []
Work days: [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY]
Weekend: [SUNDAY, SATURDAY]
这个示例展示了如何创建和使用 EnumSet
,包括使用 allOf()
、noneOf()
、range()
和 complementOf()
方法创建不同类型的 EnumSet
。
List
是一个接口,它表示一个有序的集合,并且允许存储重复的元素。List
接口是 Collection
接口的子接口,它定义了一系列操作列表的方法,例如添加元素、删除元素、获取元素等。
常见的 List
实现类包括:
ArrayList
:基于动态数组实现的列表,支持快速随机访问元素,但在插入和删除操作时性能略低于LinkedList
。LinkedList
:基于双向链表实现的列表,适合频繁的插入和删除操作,但在随机访问元素时性能较差。Vector
:与ArrayList
类似,但是是线程安全的,通常不推荐使用,因为它的性能比ArrayList
差。Stack
:栈的实现类,继承自Vector
,提供了后进先出(LIFO)的操作。
以下是一些常用的 List
接口的方法:
boolean add(E e)
:将指定的元素添加到列表的尾部。void add(int index, E element)
:将指定的元素插入到列表的指定位置。E get(int index)
:返回列表中指定位置的元素。int indexOf(Object o)
:返回列表中指定元素的第一个匹配项的索引,如果列表中不包含该元素,则返回 -1。boolean remove(Object o)
:从列表中删除指定元素的第一个匹配项,如果存在。int size()
:返回列表中的元素数量。
示例:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
// 创建一个ArrayList实例
List<String> list = new ArrayList<>();
// 向列表中添加元素
list.add("Apple");
list.add("Banana");
list.add("Orange");
// 获取列表中的元素
System.out.println("Elements in the list:");
for (String fruit : list) {
System.out.println(fruit);
}
// 在指定位置插入元素
list.add(1, "Grapes");
// 移除指定元素
list.remove("Orange");
// 获取元素的索引
int index = list.indexOf("Banana");
System.out.println("Index of Banana: " + index);
// 获取列表的大小
System.out.println("Size of the list: " + list.size());
}
}
这段代码演示了如何使用 ArrayList
实现类来创建、添加、删除和访问列表中的元素。
Stack
类是 Java 中的栈实现,它继承自 Vector
类,并提供了一组后进先出(LIFO)的操作方法。栈通常用于实现一些需要后进先出顺序的场景,比如计算机中的函数调用栈、浏览器中的历史记录等。
Stack
类的常用方法包括:
void push(E item)
:将指定元素压入栈顶。E pop()
:弹出栈顶元素,并将其从栈中移除。E peek()
:获取但不移除栈顶元素。boolean empty()
:判断栈是否为空。int search(Object o)
:查找指定元素在栈中的位置,如果存在则返回其在栈中的距离(1 表示位于栈顶,2 表示位于栈顶下方,以此类推);如果不存在,则返回 -1。
以下是一个简单的示例,演示了如何使用 Stack
类:
import java.util.Stack;
public class Main {
public static void main(String[] args) {
// 创建一个栈实例
Stack<String> stack = new Stack<>();
// 将元素压入栈顶
stack.push("Apple");
stack.push("Banana");
stack.push("Orange");
// 弹出栈顶元素
String top = stack.pop();
System.out.println("Popped element: " + top);
// 获取但不移除栈顶元素
String peeked = stack.peek();
System.out.println("Peeked element: " + peeked);
// 判断栈是否为空
boolean isEmpty = stack.empty();
System.out.println("Is stack empty? " + isEmpty);
// 查找元素在栈中的位置
int index = stack.search("Banana");
System.out.println("Index of Banana: " + index);
}
}
在这个示例中,我们创建了一个 Stack
实例,并使用 push
方法将元素压入栈顶,然后使用 pop
方法弹出栈顶元素。我们还使用了 peek
方法获取但不移除栈顶元素,并使用 empty
方法判断栈是否为空。最后,我们使用 search
方法查找指定元素在栈中的位置。
Set
是一种集合接口,它代表了一组不包含重复元素的集合。Set
接口继承自 Collection
接口,因此它具有集合的基本操作,如添加、删除、检查元素等。
Set
接口的常见实现类包括:
HashSet
:基于哈希表实现,不保证元素的顺序,允许使用null
元素。TreeSet
:基于红黑树实现,可以确保元素的排序顺序。LinkedHashSet
:继承自HashSet
,使用链表维护元素的插入顺序,可以保证元素的迭代顺序与插入顺序一致。
Set
接口的主要特点包括:
- 不允许重复元素:
Set
集合中的元素是唯一的,即集合中不会包含重复的元素。 - 无序性(或者特定顺序性):
Set
集合通常不保证元素的顺序,即元素在集合中的排列顺序可能是不确定的。 - 可以包含
null
元素:Set
集合允许包含一个null
元素,且只能包含一个。
以下是一个示例,展示了如何使用 HashSet
类来创建和操作集合:
import java.util.HashSet;
import java.util.Set;
public class Main {
public static void main(String[] args) {
// 创建一个 HashSet 实例
Set<String> set = new HashSet<>();
// 添加元素到集合中
set.add("Apple");
set.add("Banana");
set.add("Orange");
set.add("Apple"); // 添加重复元素
// 输出集合的大小
System.out.println("Size of set: " + set.size());
// 遍历集合并输出元素
System.out.println("Elements in set:");
for (String element : set) {
System.out.println(element);
}
// 检查集合是否包含指定元素
System.out.println("Contains Banana? " + set.contains("Banana"));
// 删除指定元素
set.remove("Orange");
// 清空集合
set.clear();
// 检查集合是否为空
System.out.println("Is set empty? " + set.isEmpty());
}
}
在上面的示例中,我们创建了一个 HashSet
实例,并向其中添加了几个元素。由于 HashSet
不允许包含重复元素,因此在添加重复元素时,集合的大小没有增加。然后,我们遍历集合并输出了其中的元素,使用 contains
方法检查集合是否包含指定元素,并使用 remove
方法删除了指定元素。最后,我们使用 clear
方法清空了集合,并使用 isEmpty
方法检查集合是否为空。
Map
是一种键值对的集合,它将键映射到值。 每个键都必须是唯一的,但是值可以重复。Map
接口定义了一系列方法来操作键值对集合,包括添加、删除、获取、检查键值对等操作。
Map
接口的常见实现类包括:
HashMap
:基于哈希表实现,不保证键值对的顺序,允许使用null
键和null
值。TreeMap
:基于红黑树实现,可以按照键的自然顺序或者自定义顺序对键值对进行排序。LinkedHashMap
:继承自HashMap
,使用双向链表维护键值对的插入顺序,可以保证遍历顺序与插入顺序一致。
Map
接口的主要特点包括:
- 键的唯一性:
Map
中的键是唯一的,即同一个键只能对应一个值。 - 无序性(或者特定顺序性):
Map
集合通常不保证键值对的顺序,即键值对在集合中的排列顺序可能是不确定的。 - 可以包含
null
键和null
值:Map
集合允许包含一个null
键和多个null
值。
以下是一个示例,展示了如何使用 HashMap
类来创建和操作映射:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// 创建一个 HashMap 实例
Map<String, Integer> map = new HashMap<>();
// 添加键值对到映射中
map.put("Apple", 10);
map.put("Banana", 20);
map.put("Orange", 15);
map.put("Apple", 30); // 替换已存在的键对应的值
// 获取指定键对应的值
System.out.println("Value of Apple: " + map.get("Apple"));
// 遍历映射并输出键值对
System.out.println("Entries in map:");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
// 检查映射是否包含指定键
System.out.println("Contains key Banana? " + map.containsKey("Banana"));
// 删除指定键对应的值
map.remove("Orange");
// 清空映射
map.clear();
// 检查映射是否为空
System.out.println("Is map empty? " + map.isEmpty());
}
}
在上面的示例中,我们创建了一个 HashMap
实例,并向其中添加了几个键值对。由于 HashMap
不允许包含重复键,因此在添加重复键时,旧的值会被新的值所替换。然后,我们使用 get
方法获取指定键对应的值,使用 entrySet
方法遍历映射并输出其中的键值对,使用 containsKey
方法检查映射是否包含指定键,使用 remove
方法删除指定键对应的值,最后使用 clear
方法清空映射,并使用 isEmpty
方法检查映射是否为空。
Set和Map: Set 用于存储一组唯一的元素,而 Map 用于存储键值对的映射关系。在选择使用时,根据需求和特定场景来确定使用 Set 还是 Map。
队列(Queue)是一种基本的数据结构,遵循先进先出(FIFO)的原则,即先进入队列的元素会先被取出。 Java 中的队列通常用于实现缓冲区、任务调度等场景。Java 提供了多种队列的实现,常见的包括 LinkedList
、ArrayDeque
和 PriorityQueue
。
Queue 接口定义了一系列方法,包括:
boolean add(E e):将指定的元素插入队列,如果队列已满则抛出异常。
boolean offer(E e):将指定的元素插入队列,如果队列已满则返回 false。
E remove():移除并返回队列的头部元素,如果队列为空则抛出异常。
E poll():移除并返回队列的头部元素,如果队列为空则返回 null。
E element():返回队列的头部元素,但不移除,如果队列为空则抛出异常。
E peek():返回队列的头部元素,但不移除,如果队列为空则返回 null。
- LinkedList:
LinkedList
是双向链表实现的队列,可以作为队列或双端队列使用。- 它支持在队列的两端进行添加、删除元素操作。
LinkedList
实现了Queue
接口,因此可以直接用作队列。
Queue<Integer> queue = new LinkedList<>();
queue.offer(1); // 入队
queue.offer(2);
int front = queue.peek(); // 查看队首元素
int removedElement = queue.poll(); // 出队
- ArrayDeque:
ArrayDeque
是数组实现的双端队列,也可以作为队列使用。- 它支持高效的在队列两端进行添加、删除元素操作,但不支持随机访问。
ArrayDeque
实现了Queue
接口,因此也可以直接用作队列。
Queue<Integer> queue = new ArrayDeque<>();
queue.offer(1); // 入队
queue.offer(2);
int front = queue.peek(); // 查看队首元素
int removedElement = queue.poll(); // 出队
- PriorityQueue:
PriorityQueue
是基于优先级堆实现的优先级队列。- 元素在插入时会根据优先级进行排序,每次出队操作会弹出优先级最高的元素。
PriorityQueue
实现了Queue
接口,因此也可以直接用作队列。
Queue<Integer> queue = new PriorityQueue<>();
queue.offer(3); // 入队
queue.offer(1);
int front = queue.peek(); // 查看队首元素(最小值)
int removedElement = queue.poll(); // 出队(弹出最小值)
这些是 Java 中常用的队列实现方式,选择合适的队列取决于具体的应用场景和需求。