Java(JDK1.9)集合框架归纳总结——Collection接口的第一层接口和抽象类

注:该系列文章总结自JDK1.9源码的文档注释和源码,我对源码的部分中文注释已经同步到Github:https://github.com/Dodozhou/JDK

Collection的第一层接口和抽象类

Collection第一层常用接口、类继承体系:

Collection的直接后继有3个接口和一个抽象类。3个接口分别是

  • List:Collection接口的有序集合实现,也叫做sequence。这个接口的用户可以精确控制元素在哪里插入。同时,用户可以通过元素的数字索引(在list中的位置,下标)来访问元素。允许重复值,允许null。
  • Set:不允许重复元素的集合,最多允许一个null值。正如其名称所暗示的,这个接口模拟了数学集的抽象。
  • Queue:一种用于在处理前保存元素的集合,即队列。除了继承自Collection的基本操作外,该接口还提供了额外的插入、提取和检查操作。它的这些方法都存在两种形式:当操作失败时,一种抛出异常,一种返回一个特殊的值(null或者false)。也正是由于第二种形式的存在,该接口不允许null值。

一个抽象类是:

  • AbstractCollection:该类提供了接口Collection的框架实现,用来降低实现该接口的复杂程度。这个类中,对Collection接口中的大部分方法进行了简单实现,如contains(Object 0)。这些实现只是完成了基本功能,效率并不高,具体实现应该重写这些方法来提高效率。

一、List

List的特点在上面有过概述。它不同于set,List允许重复元素。更确切地说,List允许满足e1.equals(e2)的两个元素e1,e2同时存在。如果这个List允许null值,那么也同样允许重复的null值(根据equals方法的源码可知)。
List接口提供了4个通过下标来访问元素的方法:get(int)、set(int,E)、add(int,E)、remove(int)。在某些实现中(如LinkedList),这些操作所花费的时间可能与下标大小成正比。因此,如果用户不知道这种集合的具体实现,那么使用迭代器比使用下标来访问元素更加可靠。

List接口提供了一个特有的迭代器——ListIterator。这个迭代器除了提供插入和修改等正常操作之外,还允许双向访问。该接口还提供了一个从特定位置开始方法的迭代器方法。

该接口提供了两个用于搜索特定元素的方法:get(int)、contains(Object)。出于性能的考虑,这些搜索方法要慎用。因为很多实现采用的是昂贵的线性搜索。

该接口提供了两个在列表中的任一点插入和删除多个元素的方法:add(int,E)、remove(int).

* List.Of()方法*

在JDK1.9中,该接口也提供了同Map接口中一样的Of()方法。这些静态工厂方法可以很方便地创建不可变的List。这些List包含如下特点:

  • 他们是结构不可更改的。不能添加、删除或者更新键值。进行这些操作将抛出UnsupportedOperationException
  • 如果所有元素都可以被序列化,那么这个List也可以被序列化
  • 不可变List中元素的顺序和原始List相同
  • 产生的不可变List是基于值的(不是基于引用)。

因为工厂可能会选择创建新的实例或者返回旧有的实例。因此,对这些实例引用敏感的操作(如==、hashcode和同步)是不可靠的,应该尽量避免。

这样Of方法包含11个,参数从0~10个E。还有一个可变参数的of(E… elements)。

二、Set

Set是一个不允许重复元素的集合,最多允许一个null值。正如其名称所暗示的,这个接口模拟了数学集的抽象。Set对所有构造器和add、equals、hashCode方法上添加了额外的规定。关于构造函数的附加规定是,所有构造函数都必须创建一个不包含重复元素的集合。

各个不同的实现对元素有不同的限制,例如,有的不允许null值,有的对元素类型有限制。如果插入不被允许的元素,将会抛出未检查异常,通常是NullPointerException 或者 ClassCastException。

它同样实现了11个Set.Of()方法。这些静态工厂方法的特点是:

  • 他们是结构不可更改的。不能添加、删除或者更新键值。进行这些操作将抛出UnsupportedOperationException
  • 他们不允许出现null值,否则会抛出NullPointerException。
  • 如果所有元素都可以被序列化,那么这个List也可以被序列化
  • 它们拒绝重复元素,如果重复元素别传递给这些方法,那么会抛出IllegalArgumentException。

三、Queue

这个接口定义了一种用于在处理前保存元素的集合,即队列。除了继承自Collection的基本操作外,该接口还提供了额外的插入、提取和检查操作。它的这些方法都存在两种形式:当操作失败时,一种抛出异常,一种返回一个特殊的值(null或者false)。也正是由于第二种形式的存在,该接口不允许null值。

它们的两种类型方法对比如下所示:

Summary of Queue methods
Throws exception Returns special value
Insert add(e) offer(e)
Remove remove() poll()
Examine element() peek()

典型的队列都是按照先进先出的顺序,但是这并不是一定。例如优先级队列PriorityQueue,它按照元素的优先级对元素进行排序。
在先进先出的队列里,元素通常都是从尾部插入的,头部移除的。其他的队列可能会有不同的放置规则。
队列通常不实现自己的equals和hashCode方法,而是使用继承自Object的这些方法。
因为对于相同元素但不同顺序的队列,基于队列值的equals和hashCode方法并不总是表现的很好。

为什么Queue不允许插入null值?

队列的实现通常不允许插入null值,但是一些实现,如LinkedList并不禁止null值的插入。但就算在这些不禁止的实现中,null值也是不应该别插入到队列中的,因为在poll方法中,null作为出队失败的标志。

为什么要有第二种——失败返回特定值的方法?

在容量固定的队列,如生产者消费者队列中,队列容量有限,插入和失败操作都是很正常的,因此需要有offer、poll这样失败不会抛异常,而是仅仅返回一个标志的方法。

四、AbstractCollection

该类提供了接口Collection的框架实现,用来降低实现该接口的复杂程度。该抽象类并没有添加新的特性,而是对Collection的大部分方法进行了简单功能的实现。它定义了自己的toString方法:

public String toString() {
        Iterator it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }

通过使用中括号和逗号来将元素打印出来。

它没有实现的方法有:

  • public abstract Iterator iterator();
  • public abstract int size();
  • public boolean add(E e)该方法直接抛出了一个UnsupportedOperationException,需要支持的子类去重写。

你可能感兴趣的:(语言——Java——基础)