来,一起阅读源码,通过LinkedList回顾基础

前言本文基于jdk1.8
书接上回 , 在简单介绍ArrayList的时候 , 提到了ArrayList实现了RandomAccess接口 , 拥有随机访问的能力 , 当时说到了这个接口配合LinkedList理解更容易 。 今天就来还愿了 , 开始阅读LinkedList 。
LinkedList也算我们比较常用的几个集合之一了 , 对普通程序员来说 ,
List list1 = new ArrayList()List list2 = new LinkedList() , 该怎么选择?
其实二者最大的区别在于实现方式的不同 , 只看名称我们也能知道 ,ArrayList基于数组 , 而LinkedList基于链表 , 所以关键在于数组和链表有啥区别 。
说到这 , 是不是又说明了一个很重要的道理 , 基础 , 基础 , 基础 。 如果想成为一个真正的程序员 , 不管你是科班还是半路出家 , 都要下功夫夯实基础 。
说回正题 , ArrayList基于数组 , 查找快(按索引查找) , 增删慢;LinkedList基于链表 , 增删快 , 查找慢 。 但这只是相对的 , 仅仅知道这两点 , 远远不够 , 所以 , 继续往下看 。
类签名public class LinkedListextends AbstractSequentialListimplements List, Deque, Cloneable, java.io.Serializable
来,一起阅读源码,通过LinkedList回顾基础文章插图
鉴于前一篇有很多遗漏 , 这里多说明一下:
泛型
集合类在1.5开始的版本中都采用了泛型 , 也就是 , 最主要的作用就是编译期检查 , 避免添加进不合理的类型 。 简单说:
不用泛型 , List list1 = new LinkedList();此时默认类型是Object , 也就是可以添加任意类型元素 , 在取出元素时 , 就需要强制类型转换 , 增加了出错几率 。
使用泛型 , List list2 = new LinkedList();其中 , 等号右边String可以省略 。 此时 , 编译时会执行检查 , 添加非String类型元素直接编译不通过 , 而获取时也不需要强制类型转换 。 当然 , 这里涉及到了不同时期的类型擦除 , 不是本文重点 , 后期有需要的话再专门写一下 。
因为我们使用集合绝大部分情况都是希望存储同一种类型 , 所以使用泛型(提前声明类型)很重要 。 这里也体现了一种思想:错误越早暴露越好 。
Serializable和Cloneable
实现Cloneable, Serializable接口 , 具有克隆和序列化的能力 。
Deque
实现了Deque接口 ,而Deque接口又继承了Queue接口 , 这也意味着LinkedList可以当队列使用 , 实现“先进先出” 。
List和AbstractList
在上一篇文章中 , 有一个细节没有说到 , 可能很多人也有疑问 ,为啥抽象类AbstractList已经实现了List接口 , ArrayList在继承AbstractList的同时还要再次实现List接口?换到今天的主角 , LinkedList继承了AbstractSequentialList , 而AbstractSequentialList继承了AbstractList , 为啥LinkedList还要单独实现List接口?
来,一起阅读源码,通过LinkedList回顾基础文章插图
在Stack Overflow上看到两个回答:
一位网友说问过了设计这个类的作者本人 , 作者本人表示这是当时设计时的一个缺陷 , 就一直遗留下来了 。 (当然 , 我个人觉得这个说法有待考证) 。
第二位网友举例表明了不直接再次实现List接口 , 使用代理时可能会出现意想不到的结果 。 (从实际的角度看有道理 , 但是细想之下集合类在jdk1.2已经出现 , 代理类出现在 1.3 , 逻辑上有点疑问 。 )
我个人的理解:
大神在设计集合类的时候充分考虑到了将来优化时的情况 。
具体来讲 , 这里主要在于如何理解接口和抽象类的区别 , 尤其是在java8之前 。 接口是一种规范 , 方便规划体系 , 抽象类已经有部分实现 , 更多的是帮助我们减少重复代码 , 换言之 ,这里的抽象类就相当于一个工具类 , 只不过恰好实现了List接口 , 而且鉴于java单继承 , 抽象类有被替换的可能 。
在面向接口编程的过程中 , List list= new LinkedList();如果将来LinkedList有了更好的实现 , 不再继承AbstractSequentialList抽象类 , 由于本身已经直接实现了List接口 , 只要内部实现符合逻辑 , 上述旧代码不会有问题 。 相反 , 如果不实现List , 去除继承AbstractSequentialList抽象类 , 上述旧代码就无法编译 , 也就无法“向下兼容” 。
RandomAccess接口(没实现)
LinkedList并没有实现RandomAccess接口 , 实现这个接口的是ArrayList , 之所以放在这里是为了对比 。
注意 , 这里说的随机访问的能力指的是根据索引访问 , 也就是list接口定义的E get(int index)方法 , 同时意味着ArrayList和LinkedList都必须实现这个方法 。
回到问题的本质 , 为啥基于数组的ArrayList能随机访问 , 而基于链表的LinkedList不具备随机访问的能力呢?