Java基础之集合框架详解(二)List篇

相关定义

作为Collection接口的重要子接口,List接口是一个元素有序且可重复的集合,也被称为序列。

此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

List 接口在 iterator、add、remove、equals 和 hashCode 方法的协定上加了一些其他约定,超过了 Collection 接口中指定的约定。为方便起见,这里也包括了其他继承方法的声明。

List 接口提供了 4 种对列表元素进行定位(索引)访问方法。列表(像 Java 数组一样)是基于 0 的。注意,这些操作可能在和某些实现(例如 LinkedList 类)的索引值成比例的时间内执行。因此,如果调用者不知道实现,那么在列表元素上迭代通常优于用索引遍历列表。

List 接口提供了特殊的迭代器,称为 ListIterator,除了允许 Iterator 接口提供的正常操作外,该迭代器还允许元素插入和替换,以及双向访问。还提供了一个方法来获取从列表中指定位置开始的列表迭代器。

List的相关知识点(本文将从这几个方面进行讲解):

  • 特有的方法(主要是根据索引进行查找定位)
  • ListIterator
  • List的三个重要实现类:Vector、ArrayList、LinkedList

特有的方法

  • add(int index, E element)在列表的指定位置插入指定元素(可选操作)。
  • addAll(int index, Collection< extends E> c)将指定 collection 中的所有元素都插入到列表中的指定位置(可选操作)。
  • get(int index)返回列表中指定位置的元素。
  • indexOf(Object o)返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
  • lastIndexOf(Object o)返回此列表中最后出现的指定元素的索引;如果列表不包含此元素,则返回 -1。
  • listIterator()返回此列表元素的列表迭代器(按适当顺序)。
  • listIterator(int index)返回列表中元素的列表迭代器(按适当顺序),从列表的指定位置开始。
  • remove(int index)移除列表中指定位置的元素(可选操作)。
  • set(int index, E element)用指定元素替换列表中指定位置的元素(可选操作)。
  • subList(int fromIndex, int toIndex)返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。

ListIterator

在创建迭代器之后,除非通过迭代器自身的 remove 或 add 方法从结构上对列表进行修改,否则在任何时间以任何方式对列表进行修改,迭代器都会抛出ConcurrentModificationException(并发异常)。

而Iterator只提供了一个remove方法,所以如果我们想要在迭代的过程中对迭代的元素进行更多的操作呢,于是ListIterator就应运而生了。

ListIterator,即列表迭代器,允许程序员按任一方向遍历列表、迭代期间修改列表,并获得迭代器在列表中的当前位置。ListIterator 没有当前元素;它的光标位置 始终位于调用 previous() 所返回的元素和调用 next() 所返回的元素之间。长度为 n 的列表的迭代器有 n+1 个可能的指针位置。例如:
cursor positions: ^Element(0)^Element(1)^Element(2)^ … Element(n-1)^

ListIterator中的常用方法:

  • add(E e)将指定的元素插入列表(可选操作)。
  • hasNext()以正向遍历列表时,如果列表迭代器有多个元素,则返回 true(换句话说,如果 next 返回一个元素而不是抛出异常,则返回 true)。
  • hasPrevious() 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。
  • next() 如果以逆向遍历列表,列表迭代器有多个元素,则返回 true。
  • nextIndex()返回对 next 的后续调用所返回元素的索引。
  • previous()返回列表中的前一个元素。
  • previousIndex() 返回对 previous 的后续调用所返回元素的索引。
  • remove()从列表中移除由 next 或 previous 返回的最后一个元素(可选操作)。
  • set(E e)用指定元素替换 next 或 previous 返回的最后一个元素(可选操作)。

实例:

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;


public class ListText {

    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("c");

        ListIterator<String> listIterator = list.listIterator();

        while (listIterator.hasNext()) {
            System.out.println(listIterator.next());
            listIterator.add("---------------分割线-----------------");
        }

        System.out.println("以下是反向迭代");

        while (listIterator.hasPrevious()) {
            System.out.println(listIterator.previous());
        }

    }

}

运行结果:
这里写图片描述

Vector和ArrayList

这两个类都实现了List接口,他们都是有序集合,即存储在这两个集合中的元素的位置都是有顺序的,相当于一种动态的数组,我们以后可以按位置索引号取出某个元素,并且其中的数据是允许重复的,这是HashSet之类的集合的最大不同之处,HashSet之类的集合不可以按索引号去检索其中的元素,也不允许有重复的元素。

两者的区别:

1. 同步性:Vector是线程安全的,也就是说它的方法之间是线程同步的,而ArrayList是线程不安全的,它的方法之间是线程不同步的。如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会更高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们自己再去考虑和编写线程安全的代码。
2. 数据增长:ArrayList与Vector都有一个初十容量大小,当存储进它们里面的元素的个数超过容量时,就需要增加ArrayList与Vector的存储空间,每次要增加存储空间时,不是只增加一个存储单元,而是增加多个存储单元,每次增加的存储单元的个数在内存空间利用与程序效率之间要取得一定的平衡。Vector默认僧长为原来的2倍,而ArrayList的增长策略在文档中没有明确规定(从源码上看是1.5倍)。

LinkedList

LinkedList,即List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。

此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。

所有操作都是按照双重链接列表的需要执行的。在列表中编索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。

注意,此实现不是同步的。如果多个线程同时访问一个链接列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。(结构修改指添加或删除一个或多个元素的任何操作;仅设置元素的值不是结构修改。)

常用方法:

  • addFirst(E e)将指定元素插入此列表的开头。
  • addLast(E e)将指定元素添加到此列表的结尾。
  • clone() 返回此 LinkedList 的浅表副本。
  • descendingIterator() 返回以逆向顺序在此双端队列的元素上进行迭代的迭代器。
  • element()获取但不移除此列表的头(第一个元素)。
  • getFirst()返回此列表的第一个元素。
  • getLast() 返回此列表的最后一个元素。
  • peek() 获取但不移除此列表的头(第一个元素)。
  • peekFirst() 获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。
  • peekLast() 获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。
  • poll() 获取并移除此列表的头(第一个元素)
  • pollFirst() 获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
  • pollLast() 获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
  • pop() 从此列表所表示的堆栈处弹出一个元素
  • push(E e) 将元素推入此列表所表示的堆栈。

ArrayList、Vector和LinkedList的存储性能和特性

ArrayList和Vector都是使用数组方式存储数据,此数据元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要设计数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector由于使用了synchronized方法(线程安全),通常性能上较ArrayList差。
LinkedList使用双向链表实现存储,按序号索引数据需要进行前向和后项遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快索引数据慢。LinkedList也是线程不安全的,LinkedList提供了一些方法,是的LinkedList可以被当做堆栈和队列来使用。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值