这些Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改,了解Java SE 9及其后续版本中更新的语言功能的概述。
请参阅JDK发行说明,了解所有JDK版本的新功能、增强功能以及已删除或已弃用选项的信息。
许多程序员永远不需要实现自己的Collection
类。使用本章前面描述的实现可以走得相当远。然而,总有一天你可能想要编写自己的实现。在Java平台提供的抽象实现的帮助下,这相当容易。在讨论如何编写实现之前,让我们先讨论为什么可能想要编写一个实现。
以下列表列举了您可能想要实现的自定义Collection
的类型。这不是详尽无遗的列表:
Collection
实现都存储在主内存中,并在程序退出时消失。如果您希望集合在下次程序启动时仍然存在,可以通过在外部数据库上构建一个薄层来实现。这样的集合可能被多个程序同时访问。Map
。键可以表示位置,值可以通过get
操作从这些位置的传感器中读取。List
。这种列表在文本处理中经常出现,可以进行运行长度编码 - 运行可以表示为一个包含重复元素和连续重复次数的单个对象。这个例子很有趣,因为它在性能的两个方面进行了权衡:它所需的空间较少,但比ArrayList
花费更多的时间。Collection
,在允许重复元素的同时,提供常量时间的包含性检查。在HashMap
之上实现这样一个集合相当简单。Integer
的List
实例。编写自定义实现非常简单。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
— 一个既不是Set
也不是List
的Collection
。至少需要提供iterator
和size
方法。AbstractSet
— 一个Set
;使用方式与AbstractCollection
相同。AbstractList
— 由随机访问数据存储支持的List
,例如数组。至少需要提供positional access
方法(get
,可选的set
,remove
和add
)以及size
方法。抽象类会处理listIterator
(和iterator
)。AbstractSequentialList
— 由顺序访问数据存储支持的List
,例如链表。至少需要提供listIterator
和size
方法。抽象类会处理位置访问方法。(与AbstractList
相反)。AbstractQueue
— 至少需要提供offer
,peek
,poll
和size
方法以及支持remove
的iterator
。AbstractMap
— 一个Map
。至少需要提供entrySet
视图。通常使用AbstractSet
类实现。如果Map
是可修改的,则还必须提供put
方法。编写自定义实现的过程如下: