【Java基础】List集合系列

2022-05-12 19:58:26 浏览数 (1)

全文环境为JDK1.8

本篇目录

1.List 特点2. List 接口的常用方法3.ArrayList 集合4.LinkedList 集合5.Vector 集合

1 - List 特点

List接口继承至Collection接口,存储在List集合中的元素可以重复,且可以为NULL;

与Map集合不同,List集合是有序的,可以像数组一样通过索引来获取元素。

2 - List 接口常用方法

由它的继承关系可以看到List接口继承至Collection接口,所以Collection中有的方法,List也继承过来了,这里就不讲Collection的方法了。

代码语言:javascript复制
// 1-在指定位置插入元素,后面的元素都往后移一个元素
void add(int index, E element)
代码语言:javascript复制
// 2-在指定的位置中插入c集合全部的元素,如果集合发生改变,则返回true,否则返回false。
boolean addAll(int index, Collection<? extends E> c)
代码语言:javascript复制
// 3-返回list集合中指定索引位置的元素
E get(int index)
代码语言:javascript复制
// 4-返回list集合中第一次出现o对象的索引位置,如果list集合中没有o对象,那么就返回-1
int indexOf(Object o)
代码语言:javascript复制
// 5-返回此列表元素的列表迭代器(按适当顺序)
ListIterator<E> listIterator()
代码语言:javascript复制
// 6-从指定位置开始,返回此列表元素的列表迭代器(按适当顺序)。
ListIterator<E> listIterator(int index)
代码语言:javascript复制
// 7-删除指定索引的对象
E remove(int index)
代码语言:javascript复制
// 8-在索引为index位置的元素更改为element元素
E set(int index, E element)
代码语言:javascript复制
// 9-返回从索引fromIndex到toIndex的元素集合,包左不包右
List<E> subList(int fromIndex, int toIndex)

3 - ArrayList

ArrayList继承关系

毋庸置疑ArrayList集合是我们最常使用的集合之一,是List接口的一个实现类。

Cloneable是一个标记接口,只有实现这个接口后,然后在类中重写clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常。

AbstractList是一个抽象类,它也实现了List接口。

那为什么ArrayList继承它,而不是直接去实现List接口呢?

这是因为List的实现类太多了,为了减少这些类的重复代码,所以将它们写成一个抽象类。各位在开发过程中也可以用一下这个思想。

RandomAccess也是一个标记接口,只有实现这个接口后,就能支持快速随机访问。

往上追溯,可以在Collections接口中的binarySearch()方法中会判断当前的List是否实现了RandomAccess接口,然后再决定使用for循环的还是使用迭代器的形式遍历当前List

Serializable也是一个标记接口,只有实现了这个接口后,这个类才能进行序列化。

ArrayList底层数据结构

代码语言:javascript复制
transient Object[] elementData;

从它的源码中可以看到底层是Object[],所以它可以存储几乎所有类型的数据。

transient关键字的作用是在序列化这个对象时,这个属性不会被序列化。

如果对ArrayList感兴趣可以查看我另一篇对ArrayList的详解,这篇文章的重心在介绍List集合。

点击查看-ArrayList深度解析

4 - LinkedList

LinkedList继承关系

CloneableSerializable上面介绍ArrayList的时候说过了,这里就不提了。

AbstractSequentialList抽象类继承至AbstractList抽象类,而在上面有介绍后者,它俩的区别在前者只支持按次序访问,后者支持随机访问。

这就是为什么LinkedList集合没有实现RandomAccess接口,因为它不支持随机访问。

Deque接口定义了一个双端队列,它提供了一系列针对队列首尾元素的操作方法。

LinkedList实现了该接口,意味着它可以做为一个双端队列来使用。

LinkedList底层数据结构

代码语言:javascript复制
private static class Node<E> {
    E item;
    Node<E> next;
    Node<E> prev;

    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

LinkedList本质上是一个双向链表,item存储着本身的元素,next指向下一个Nodeprev指向上一个Node。如下图:

LinkedList 独有的方法

由于LinkedList实现了Deque接口,所以它有Deque接口中的方法。

代码语言:javascript复制
// 在集合的头部添加一个元素
void addFirst(E e)
代码语言:javascript复制
// 在集合的尾部添加一个元素
void addLast(E e)
代码语言:javascript复制
// 获取集合的第一个元素
E getFirst()
代码语言:javascript复制
// 获取集合的最后一个元素
E getLast()
代码语言:javascript复制
// 删除集合中第一个元素
E removeFirst()
// 删除集合中最后一个元素
E removeLast()

5 - Vector

可以从Vector的继承关系中看出,它与ArrayList应该比较相似;

VectorArrayList的底层数据结构、初始容量、扩容方式等都差不多;

不同的地方是Vector相对来说是线程安全的,因为它的大多方法都使用synchronized关键字,如果开发者对线程安全有较高的要求,推荐使用Vector

但如果您对线程安全有更高的要求,推荐您使用concurrent包下的CopyOnWriteArrayList。

对于Vector的详解,后面我会专门写一篇来介绍。

0 人点赞