Java集合丛林:深入了解集合框架的秘密

简介: Java集合丛林:深入了解集合框架的秘密

除了以 Map 结尾的类之外,其他类都实现了 Collection 接口,而以 Map 结尾的类实现了 Map 接口。

Java 集合类库将接口与实现进行分离。以最常用的 List 为例,List 接口定义的统一格式,定义多个方法的约束而不用关心具体的实现。

public interface List<E> extends Collection<E> {
  int size();
  boolean isEmpty();
  boolean contains(Object o);
  Iterator<E> iterator();
  Object[] toArray();
  <T> T[] toArray(T[] a);
  boolean add(E e);
  boolean remove(Object o);
  ...
}

研究 API 的时候会发现另外以 Abstract 开头的类,比如 AbstractList。这些是实现了相关接口的抽象类,为类库的实现者设计的。后面具体的实现可以更加轻松的扩展和重写抽象类的方法。

Collection 接口

集合类的基本接口是 Collection 接口。这个接口有定义了下面这些方法:

public interface Collection<E> extends Iterable<E> {
  // 返回集合中的元素个数。
  int size();
  // 当前集合存储的数量是否为 0。
  boolean isEmpty();
  // 集合中是否包含指定元素。
  boolean contains(Object o);
  // 返回一个实现了 Iterator 接口(迭代器)的对象。可以使用这个迭代器对象依次访问集合中的元素。
  Iterator<E> iterator();
  // 将集合中的元素返回成一个数组。
  Object[] toArray();
  // 用于向集合中添加元素。如果添加元素确实改变了集合就返回 true,如果集合没有发生变化就返回 false。
  boolean add(E e);
  // 从集合中删除一个元素。如果删除元素确实改变了集合就返回 true,如果集合没有发生变化就返回 false。
  boolean remove(Object o);
  ...
}

迭代器 Iterator

Iterator 接口包含四个方法:

public interface Iterator<E> {
  boolean hasNext();
  E next();
  default void remove();
  default void forEachRemaining(Consumer<? super E> action);
}

通过反复调用 next 方法,可以逐个访问集合中的每个元素。但是,如果到达了集合的末尾,next 方法将抛出一个 NoSuchElementException。因此,需要在调用 next 之前调用 hasNext 方法

public static void main(String[] args) {
  List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
  Iterator<Integer> iterator = list.iterator();
  while (iterator.hasNext()) {
    Integer i = iterator.next();
    System.out.println(i);
  }
}

编译器简单地将 for each 循环翻译为带有迭代器的循环。它可以与任何实现了 Iterable 接口的对象一起工作,这个接口只包含一个抽象方法:

public interface Iterable<T> {
    Iterator<T> iterator();
    ...
}   

Collection 接口扩展了 Iterable 接口。因此,对于标准类库中的任何集合都可以使用 foreach 循环。

在 Java8 中,迭代器提供了另一种迭代方式,可以调用 forEachRemaining 方法并提供一个 lambda 表达式。

public static void main(String[] args) {
  List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
  Iterator<Integer> iterator = list.iterator();
  iterator.forEachRemaining(i -> System.out.println(i));
}

元素被访问的顺序取决于集合类型。如果对 ArrayList 进行迭代,迭代器将从索引 0 开始,每迭代一次,索引值加 1, 然而,如果访问 HashSet 中的元素,每个元素将会按照某种随机的次序出现,无法预知元素被访问的次序。

应该将 Java 迭代器认为是位于两个元素之间。当调用 next 时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。

**Iterator 接口的 remove 方法将会删除上次调用 next 方法时返回的元素。**在大多数情况下,在决定删除某个元素之前应该先看一下这个元素是很具有实际意义的。然而,如果想要删除指定位置上的元素,仍然需要越过这个元素。如果调 remove 之前没有调用 next 将是不合法的,抛出一个 IllegalStateException 异常。

泛型实用方法

由于 Collection 与 Iterator 都是泛型接口,可以编写操作任何集合类型的实用方法。在 Collection 接口中定义了很多非常有用的实用方法,所有实现类都必须提供这些方法的实现。这些方法的数量还是不少的,所以为了让实现者更容易得实现这个接口,Java 提供了 AbstractCollection 类,这个抽象类将一部分的接口方法已经实现,所以具体的集合类就可以继承这个抽象类进行下一步的实现。

集合框架中的接口

集合有两个基本接口:Collection 和 Map。

List 是一个有序集合。元素会增加到容器的指定位置。可以使用迭代器和整数索引进行访问。整数索引这种方法也称为随机访问,因为可以按照任意顺序(从头、从尾、中间、指定位置)访问元素。迭代器就只能按照顺序进行访问。

Set 接口等同于 Collection 接口,不过它不允许增加重复的元素。所以要适当的定义元素类的 equals 方法和 hashCode 方法。

Map 接口定义了存储键值对类型的数据的集合,添加数据时需要调用 put(key, value)方法,一个 Map 中,key 是唯一的,所以重复添加会覆盖数据。

笔记大部分摘录自《Java核心技术卷I》,含有少数本人修改补充痕迹。


相关文章
|
5天前
|
存储 Java 容器
Java一分钟之-高级集合框架:LinkedList与TreeSet
【5月更文挑战第17天】这篇博客对比了Java集合框架中的LinkedList和TreeSet。LinkedList是双向链表,适合中间插入删除,但遍历效率低且占用空间大;TreeSet基于红黑树,保证元素有序且不重复,插入删除速度较LinkedList慢但查找快。选择时需根据操作需求和性能考虑。
14 2
|
1天前
|
并行计算 安全 算法
探索Java并发编程:Fork/Join框架的应用与优化
在多核处理器普及的今天,并发编程已经成为提高程序性能的重要手段。Java提供了多种并发工具,其中Fork/Join框架是处理分治任务的强大工具。本文将深入探讨Fork/Join框架的核心原理、使用场景以及性能优化技巧,帮助开发者更好地利用这一框架解决实际问题。通过实例分析,我们将看到如何有效地使用Fork/Join框架来加速计算密集型任务,并提供一系列最佳实践,以确保高效和线程安全的并发执行。
|
1天前
|
存储 Java 容器
Java一分钟之-高级集合框架:LinkedList与TreeSet
【5月更文挑战第21天】本文对比了Java集合框架中的LinkedList和TreeSet。LinkedList是双向链表,实现List接口,适合中间插入删除,但遍历效率低;TreeSet基于红黑树,实现Set接口,保证元素有序且无重复,插入删除速度较LinkedList慢,但查找排序快。选择时应根据具体需求考虑操作频率和排序需求。
12 1
|
3天前
|
安全 Java 容器
Java一分钟之-并发编程:线程安全的集合类
【5月更文挑战第19天】Java提供线程安全集合类以解决并发环境中的数据一致性问题。例如,Vector是线程安全但效率低;可以使用Collections.synchronizedXxx将ArrayList或HashMap同步;ConcurrentHashMap是高效线程安全的映射;CopyOnWriteArrayList和CopyOnWriteArraySet适合读多写少场景;LinkedBlockingQueue是生产者-消费者模型中的线程安全队列。注意,过度同步可能影响性能,应尽量减少共享状态并利用并发工具类。
17 2
|
4天前
|
安全 Java 容器
Java一分钟之-高级集合框架:并发集合(Collections.synchronizedXXX)
【5月更文挑战第18天】Java集合框架的`Collections.synchronizedXXX`方法可将普通集合转为线程安全,但使用时需注意常见问题和易错点。错误的同步范围(仅同步单个操作而非迭代)可能导致并发修改异常;错误地同步整个集合类可能引起死锁;并发遍历和修改集合需使用`Iterator`避免`ConcurrentModificationException`。示例代码展示了正确使用同步集合的方法。在复杂并发场景下,推荐使用`java.util.concurrent`包中的并发集合以提高性能。
17 3
|
4天前
|
Java 开发者
Java一分钟之-高级集合框架:优先队列(PriorityQueue)
【5月更文挑战第18天】`PriorityQueue`是Java集合框架中的无界优先队列,基于堆数据结构实现,保证队头元素总是最小。常见操作包括`add(E e)`、`offer(E e)`、`poll()`和`peek()`。元素排序遵循自然排序或自定义`Comparator`。常见问题包括错误的排序逻辑、可变对象排序属性修改和混淆`poll()`与`peek()`。示例展示了自然排序和使用`Comparator`的排序方式。正确理解和使用`PriorityQueue`能提升应用性能。
37 6
|
4天前
|
存储 Java
Java一分钟之-高级集合框架:Queue与Deque接口
【5月更文挑战第18天】本文探讨Java集合框架中的`Queue`和`Deque`接口,两者都是元素序列的数据结构。`Queue`遵循FIFO原则,主要操作有`add/remove/element/peek`,空队列操作会抛出`NoSuchElementException`。`Deque`扩展`Queue`,支持首尾插入删除,同样需注意空`Deque`操作。理解并正确使用这两个接口,结合具体需求选择合适数据结构,能提升代码效率和可维护性。
29 4
|
7天前
|
存储 安全 Java
java集合框架及其特点(List、Set、Queue、Map)
java集合框架及其特点(List、Set、Queue、Map)
|
6月前
|
Java
Java集合框架“List“
Java集合框架“List“
49 1
|
7天前
|
Java 程序员
Java集合框架:List、Set、Map类型及泛型详解
Java集合框架:List、Set、Map类型及泛型详解