055.JAVA集合框架_List接口及其实现类


博主的 Github 地址


1. List 接口及其实现类

  • 根据 Vector 类, Stack 类, ArrayList 类和 LinkedList 类,
    这四个实现类所拥有的存储特点方法进行总结, 得出共同特点:

    • 允许集合内部存在重复的元素
    • 会记录添加元素的先后顺序
  • 因此自下而上来说可以根据这些实现类总结出一个接口, 就是 List 接口.

  • List 接口是有序的 collection (也称为序列). 它的特点是:

    • 列表中允许存在重复的元素
    • 用户可以对列表中每个元素的插入位置进行精确地控制
    • 用户可以根据元素的整数索引(在列表中的位置)访问并搜索元素
  • 此接口是 Java Collections Framework 的成员.


1.1. Vector 类

  • Vector 类可以实现可增长的对象数组, 它包含可以使用整数索引进行访问的元素.

  • 它的大小可以根据需要增大或缩小, 以适应创建 Vector 后进行添加或移除项的操作.

  • 该类中的方法是支持同步的, 该类底层实际上是 Object 数组.

1.1.1. Vector 类的存储原理
  • 通过查看源码可以知, Vector 类中定义了一个 Object 类型的数组成员变量.
    定义的代码为: protected Object[] elementData;

    • 因此表面上是将数据存到 Vector 对象中, 实际是存在 Object 数组中的.

    • 同时数组元素类型是 Object 类型, 因此集合中只能存储任意类型的对象.
      在低版本 JAVA 中集合框架是不支持存储基本数据类型的.
      但 JAVA5 后会自动装箱拆箱, 因此写入基本类型时不会出错.

    • 集合中存储的对象, 都是对象的引用, 而非对象本身.


1.2. Stack 类

1.2.1. Stack 类的简介
  • Stack 类代表先进先出(LIFO)栈的对象. 它继承自 Vector 类, 允许一个向量被视为栈.

  • 要实现栈这种数据结构, 底层可使用数组或链表进行操作, Stack 类继承父类 Vector, 因为 Vector 类定义了 Object 数组成员的, 因此 Stack 类将该数组成员继承了,
    所以 Stack 类底层是用数组来实现栈的.

  • 对于栈结构实现的集合框架官方建议:
    Deque 接口及其实现提供更完整和一致的 LIFO 堆栈操作集, 这些接口应优于此类.
    例如下面利用其实现类来进行定义的一个栈:

    Deque<Integer> stack = new ArrayDeque<Integer>(); 
1.2.2. Stack 常用的方法
  • Stack 类在 Vector 类的基础上增加了 5 个操作:
    • 常规的入栈出栈, push()pop() 操作;
    • 查看栈顶元素的 peek() 方法;
    • 以测试堆栈是否为空的 empty() 方法;
    • 以及返回一个对象在此堆栈上的基于 1 的位置的 search() 方法.

1.3. ArrayList 类

1.3.1. ArrayList 类的简介
  • List 接口的大小可变数组的实现. 实现了所有可选列表操作, 并允许存放所有元素.

  • 除了实现 List 接口外, 该类还提供了一些方法来操纵内部的存储列表的数组大小.
    (这个类是大致相当于 Vector, 不同之处在于它是不同步的).

  • ArrayList 类是 JAVA 集合框架出现后用来取缔 Vector 类的.

    • 二者的底层原理是基于数组的算法, 几乎是一模一样的.
  • ArrayList 类和 Vector 类的最大区别是在于有没有用同步修饰

    • ArrayList 中的所有方法没有使用 synchronized 修饰;
    • Vector 类中的所有方法都使用了 synchronized 修饰.
  • 因此 ArrayList 类的性能比 Vector 类更高, 但线程安全程度相对要低.

  • 但可通过集合工具类使得 ArrayList 类线程安全, 因此彻底取缔 Vector 类.

    • 工具类调用实例如下所示:
      List list = Collections.synchronizedList(new ArrayList(...)); 
1.3.2. ArrayList 类的源码分析
  • 从底层源码来互相对比 Vector 类和 ArrayList 类, 可以发现它们的设计差异很大.

  • 这种设计差异源自于 JAVA7 之后对 ArrayList 类的设计重新进行优化, 使其性能更高.
    在 JAVA6 及其之前, Vector 类和 ArrayList 类的源码除了同步修饰外是一样的.

  • 最直观的优化在于初始化 Object 数组上.

    • Vector 类默认初始化数组长度为 10, 不论增加数据与否都占用了内存空间;
    • ArrayList 类则默认初始化长度是 0 的空数组, 得到的是一个不占空间的空集;
      只有在第一次调用 add() 方法的时候才会再次对数组赋予空间进行存储.
  • ArrayList 类优化后节省了空间, 以及可通过返回 new ArrayList() 来返回空集 [].


1.4. LinkedList 类

1.4.1. LinkedList 类的简介
  • List 接口的链接列表实现. 实现所有可选的列表操作,并且允许所有元素, 包括 null.

  • 除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾对元素的操作,
    包括 get, removeinsert 元素提供了统一的命名方法.

  • LinkedList 类还实现了单向和双向队列的接口, 也提供了栈和链表的操作方法.
    因此 LinkedList 类可用于实现栈和双向链表, 单向/双向队列这几种数据结构.

  • 但由于是多种数据结构的实现类, 导致继承和实现了多种方法, 但实际上很多方法
    其功能都是重复的, 只是名字不同而已.

  • 同时该类也是不同步的, 也需要调用集合工具类的方法来提供一个线程安全的链表.

    List list = Collections.synchronizedList(new LinkedList(...));
1.4.2. LinkedList 类的方法解析
  • 不论是链表还是队列, 都特别擅长操作头部和尾部的节点.
    因此在 LinkedList 类中大多数方法命名都为 xxFirst/xxLast.

  • 值得注意的是链表中并没有索引的概念, 但 LinkedList 类仍能使用
    E get(int index) 方法来进行索引查询, 这是因为从 JAVA2 开始,
    LinkedList 类作为 List 接口的实现类, 而接口中提供了该方法,
    所以 LinkedList 类内部也只能提供一个变量来模拟当做索引使用.
    因此使用 LinkedList 类时, 尽量不要去使用索引查询, 性能非常低.
    LinkedList 类性能高的地方在于删除和保存操作, 而非去查询检索.

  • 具体操作方式可以直接去查询 API 获取.


2. List 的实现类性能和特点分析

  • 这里只讨论 Vector 类, ArrayList 类和 LinkedList 类.

2.1. 实现类之间的区别

  • 共同点已经在上面所总结, 现在这里总结这四种实现类之间的不同点:

    • Vector 类: 底层采用数组结构算法, 方法都是同步的

    • ArrayList 类: 底层采用数组结构算法, 方法不是同步的

    • LinkedeList 类: 底层采用双向链表结构算法, 方法不是同步的

2.2. 数组结构和双向链表结构的算法性能

  • List 的实现类的底层有数组结构和双向链表两种, 应用着不同的算法.

    • 数组结构算法: 查询和更改性能高, 插入和删除性能低
    • 链表结构算法: 插入和删除性能高, 查询和更改性能低
  • 因此在使用的时候根据不同的应用场景选择不同的实现类,
    Vector 类已被 ArrayList 类取代, 不再适用.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值