Java 教程是为 JDK 8 编写的。本页中描述的示例和实践未利用在后续版本中引入的改进。
许多程序员永远不需要实现自己的 Collection
类。你可以使用本章前面部分中描述的实现进行相当久的操作。但是,有一天你可能想编写自己的实现。借助 Java 平台提供的抽象实现,这很容易做到这一点。在我们讨论 如何 编写实现之前,让我们讨论一下为什么要编写一个实现。
以下列表说明了你可能希望实现的自定义 Collection
的类型。它并非详尽无遗:
Collection
实现都驻留在主内存中,并在程序退出时消失。如果你希望下次程序启动时仍然存在的集合,你可以通过在外部数据库上构建胶合代码来实现它。这样的集合可以由多个程序同时访问。Map
。键可以表示位置,并且可以响应 get
操作从这些位置处的传感器读取值。List
。这种在文本处理中经常出现的列表可以是 run-length encoded (游程编码)。run 可以表示为包含重复元素和连续重复次数的单个对象。这个例子很有意思,因为它会影响性能的两个方面:它比 ArrayList
需要更少的空间但更多的时间。Collection
在允许重复元素的同时提供包含检查的常量时间。在 HashMap
上实现这样的集合是相当简单的。List
实例来表示连续范围的 Integer
。编写自定义实现非常简单。Java 集合框架提供了明确设计的抽象实现,以方便自定义实现。我们将从以下 Arrays.asList
的实现示例开始。
public static <T> List<T> asList(T[] a) { return new MyArrayList<T>(a); } private static class MyArrayList<T> extends AbstractList<T> { private final T[] a; MyArrayList(T[] array) { a = array; } public T get(int index) { return a[index]; } public T set(int index, T element) { T oldValue = a[index]; a[index] = element; return oldValue; } public int size() { return a.length; } }
信不信由你,这非常接近 java.util.Arrays
中包含的实现。就这么简单!你提供构造函数和 get
,set
和 size
方法,AbstractList
完成其余所有操作。你可以免费获得 ListIterator
,批量操作,搜索操作,哈希码计算,比较和字符串表示。
假设你希望实现更快一点。抽象实现的 API 文档精确描述了每个方法的实现方式,因此你将知道要覆盖哪些方法以获得所需的性能。前面的实现的性能很好,但可以稍微改进一下。特别是,toArray
方法遍历 List
,一次复制一个元素。鉴于内部表示,克隆数组的速度更快,更明智。
public Object[] toArray() { return (Object[]) a.clone(); }
通过添加此覆盖以及更多类似覆盖,此实现正是 java.util.Arrays
中的实现。为了完全公开,使用其他抽象实现有点困难,因为你必须编写自己的迭代器,但它仍然不是那么困难。
以下列表总结了抽象实现:
AbstractCollection
Collection
既不是 Set
也不是 List
。至少,你必须提供 iterator
和 size
方法。AbstractSet
Set
; 使用与 AbstractCollection
相同。AbstractList
List
由随机访问数据存储(例如数组)支持。至少,你必须提供 位置访问
方法(get
,并且,可选地,set
,remove
,以及 add
)和 size
方法。抽象类负责 listIterator
(和 iterator
)。AbstractSequentialList
List
,由顺序访问数据存储(例如链表)支持。你必须至少提供 listIterator
和 size
方法。抽象类负责位置访问方法。(这与 AbstractList
相反。)AbstractQueue
至少,你必须提供 offer
,peek
,poll
和 size
方法以及 iterator
支持 remove
。AbstractMap
Map
。你至少必须提供 entrySet
视图。这通常使用 AbstractSet
类实现。如果 Map
是可修改的,则还必须提供 put
方法。编写自定义实现的过程如下: