前言

Java集合框架概述; 主要总述Java集合框架的设计理念, 组成和基本接口(及其区别等)

    一. 设计理念

    1. 在Java 2之前,Java是没有完整的集合框架的。它只有一些简单的可以自扩展的容器类,比如Vector,Stack,Hashtable等)

    2. Java集合其实就是一组对象的集合

    3. 独立于实现细节, 方便重用, 保证向下兼容(即保留了Vector等旧的API)

    4. 加强了API之间的互通信, 减少了新API的学习: 提供尽量统一的接口

    二. 基本组成

    2.1 总述

    Java集合框架主要分为三个部分: 接口, 实现和算法

    2.1-1 接口

    接口指的是以CollectionMap为起始的一系列公用接口

    实际上从Map出发的并不是真正的集合, 只是其包含集合视图操作, 所以也将其归入集合框架中

    Collection出发的公用接口主要有以下几个, 也是这次会着重讲解和比较的; 当然, 下面的接口并不全面, 在后面会逐渐扩展和补充

    集合框架基本接口

    Map出发的公用接口如下

    集合框架基本接口

    当然, 上述列举出来的子接口都是直接继承自Collection或者Map, 对于其子接口的子接口, 这里并没有列出在这里(比如NavigableMap接口是SortedMap接口的子接口, 而不是直接继承Map的, 所以这里并没有直接列出来)

    2.1-2 实现

    实现指的是接口的实现类, 这里笔者在官网找到一张表, 如下, 很好的列出了平时重点所用的实现类

    InterfaceHash TableResizable ArrayBalanced TreeLinked ListHash Table + Linked List
    SetHashSet
    TreeSet
    LinkedHashSet
    List
    ArrayList
    LinkedList
    Deque
    ArrayDeque
    LinkedList
    MapHashMap
    TreeMap
    LinkedHashMap

    当然, 还应该包含Java 2以前几个旧API, 即: VectorStackHashtable

    2.1-3 算法

    (1). 算法

    算法指的是以Collections为主的提供的一系列对集合的操作, 参见下图, 列出了其提供的常用算法

    集合框架基本接口

    下面对上述方法进行一些简单解释

    1. sort(List): 使用归并排序, 保证NlogN的时间复杂度和稳定性

    2. binarySearch(List, Object): 在一个有序的List中使用二分查找

    3. reverse(List): 逆转List

    4. shuffle(List): 将List中的元素随机重排

    5. fill(List, Object): 使用指定值(Object)覆盖List中所有元素

    6. copy(List dest, List src): 拷贝

    7. min(Collection): 返回最小值

    8. max(Collection): 返回最大值

    9. rotate(List list, int distance): 将List中元素旋转指定distance

    10. replaceAll(List list, Object oldVal, Object newVal): 将List中出现的所有oldVal替换为newVal

    11. indexOfSubList(List source, List target): 返回source中与target匹配的第一个子项的首元素索引

    12. lastIndexOfSubList(List source, List target): 返回最后一个匹配子项的首元素索引

    13. swap(List, int, int): 交换指定位置的两个元素

    14. frequency(Collection, Object): 找出指定元素出现次数

    15. disjoint(Collection, Collection): 判断两个集合是否包含相同元素(即集合是否相交)

    16. addAll(Collection<? super T>, T...): 将指定元素添加到指定集合中

    (2). 包装类

    当然, 实际上Collections提供的不仅仅是针对集合的算法, 其还提供了一系列对集合的包装类(即Wrapper), 主要包括以下三大类:

    1. Collections.unmodifiableInterface(): 返回一个不可修改的集合, 包括UnmodifiableCollectionUnmodifiableSetUnmodifiableList; 实现原理是在修改集合的操作上(如add()remove()等)抛出异常

    2. Collections.synchronizedInterface(): 返回一个线程安全的集合, 包括SynchronizedCollectionSynchronizedSetSynchronizedList; 实现原理是在需要同步的方法上添加synchronized限制

    3. Collections.checkedInterface(): 返回一个类型检查的集合, 包括CheckedCollectionCheckedQueueCheckedSetCheckedList; 实现原理是在add()的时候进行类型检查, 如果是非法类型, 就抛出异常ClassCastException; 这里的类型检查实际上是使用Class.isInstance()来检查的, 关于该方法和instanceof运算符的区别, 参见博客; (大致上, 二者是等价的, 只是isInstance()是在运行时才进行类型检查, 故可用于反射, 泛型; 但是instanceof需要在编译时知道类的具体类型(重点理解在动态等价))

    这些包装类的作用主要是满足平时一些特殊的需求, 比如同步, 不可修改等

    三. 基本接口

    在这一节, 主要讲解上面提到的几个基本接口, 这里不会涉及到其实现类

    3.1 Collection

    Collection是集合框架中一个最顶层的基本接口, 提供了一个数据集的基本描述, 在官方API中并没有提供其直接实现类, 而是在其基础上提供了进一步的限制接口, 即ListSetQueue; 这样做的好处有:

    1. 代码复用: 从面向对象的角度讲, 抽取出一个顶级接口, 有助于用户代码复用, 即编写一个接口, 实现不同传参(Collection的各种实现类), 实际上也是利用了多态(官方文档的解释是: 实现最大通用性)

    2. 易于扩展: 符合面向对象的思想, 即将数据集抽象, 通过不同的需求对其实现不同方便的限制, 易于扩展; 同时减少新API学习成本

    Collection提供了数据操作的基本方法, 如add()remove()size()clear()等; 同时, 其还继承了Iterable接口, 这个接口是用于使用迭代器遍历集合用的, 使用迭代器遍历集合的优点是我们不必知道集合的内部结果,集合的内部结构、状态由Iterator来维持, 通过统一的方法hasNext()next()来判断和获取下一个元素

    3.2 List

    ListCollection上做的限制是, 元素有序(但并不是排序), 允许重复元素; 同时还将迭代器换成了ListIterator; 关于ListIterator, 其允许双向的迭代, 以及元素插入(ListIterator.add()), 删除(ListIterator.remove())和替换ListIterator.set()

    JDK9中, 还提供了一个List.of()的静态方法, 用于返回一个不可变List(Immutable List)

    3.3 Set

    SetCollection上做的限制是, 元素不重复, 至多一个null元素

    JDK9中, 还提供了一个Set.of()的静态方法, 用于返回一个不可变的Set

    3.4 Queue

    QueueCollection上做的限制是, 除了Collection提供的基本操作外, 还提供了一些额外的操作, 分为两类, 一个返回特定值, 另一个抛出异常, 见下表

     Throw ExceptionReturn Special Value
    Insertadd(e)offer(e)
    Removeremove()poll()
    Examineelement()peek()

    3.5 Map

    Map本质上是一组键值对, Map允许单独访问key(通过keySet()返回keySet), 也可以单独访问value(通过values()方法返回valueCollection), 也可以通过entrySet()获取key-value的对应关系。