JDK8集合类源码解析 - LinkedList
linkedList主要要注意以下几点:
1构造器
2 添加add(E e)
3 获取get(int index)
4 删除 remove(E e),remove(int index)
5 判断对象是否存在:contain(E e)
Jdk8中的linkedList基于双向链表来实现的
双向链表每个结点包含数据域,一个前指针和一个后指针,分别指向前驱结点和后继结点(如果有前驱/后继的话,没有就是null)。
另外,双向链表还有一个first指针,指向头节点,和last指针,指向尾节点。
接下来我们来看看源码
transient int size = 0;
transient Node<E> first; //整个链表的头结点
transient Node<E> last; //整个链表的尾结点
Node的数据结构如下
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;
}
}
如图所示
1构造器
有两个构造器,分别是空的和从一个集合创建。
注意:因为基于链表创建,理论上无容量的限制,不需要扩容的操作。
2 添加add(E e)
默认添加是在链表尾部添加
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
//创建一个新结点 并且把尾结点设为当前结点的前驱
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)//如果整个链表为空
first = newNode; //把当前结点设为头结点
else //不为空
l.next = newNode; //把当前结点设为尾结点的后继
size++;
modCount++;
}
3 获取get(int index)
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// assert isElementIndex(index); if (index < (size >> 1)) { //判断下标位置是在前半截还是后半截 如果在前半截
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next; //从前往后找
return x;
} else { //如果在后半截 Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;// 从后往前找
return x;
}
}
注意:1跟arraylist不同的是,linkedlist查找指定下标元素需要遍历
2 >> 1 (除以2) <<1 (乘以2)
4 删除 remove(E e),remove(int index)
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) { //先溢出第一个null
unlink(x);
return true;
}
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) { //找到了就移除
unlink(x);
return true;
}
}
}
return false;
} E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next; //当前元素的后继
final Node<E> prev = x.prev;//当前元素的前驱 if (prev == null) { //当前元素是头结点
first = next;
} else {
prev.next = next; //设置当前元素的后继为前驱的后继
x.prev = null;
} if (next == null) { //当前元素是尾结点
last = prev;
} else {
next.prev = prev;//设置当前元素的前驱为后继的前驱
x.next = null;
} x.item = null; //清空当前元素
size--;
modCount++;
return element;
}
5 判断对象是否存在:contain(E e)
public boolean contains(Object o) {
return indexOf(o) != -1;
}
public int indexOf(Object o) {
int index = 0;
if (o == null) {
//从头开始找 找到第一个null
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
//从头开始找 看有没有等于item的
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
总结:1 Jdk8中的linkedList基于双向链表来实现的,插入删除快,查询慢,适合读少写多的情况
2 linkedList还有一些有趣的方法,可以实现队列
3添加元素时不用扩容
4 线程不安全
JDK8集合类源码解析 - LinkedList的更多相关文章
- JDK8集合类源码解析 - HashSet
HashSet 特点:不允许放入重复元素 查看源码,发现HashSet是基于HashMap来实现的,对HashMap做了一次“封装”. private transient HashMap<E,O ...
- JDK8集合类源码解析 - HashMap
java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMap.Hashtable.LinkedHashMap和TreeMap HashMap ...
- JDK8集合类源码解析 - ArrayList
ArrayList主要要注意以下几点: 1构造方法 2添加add(E e) 3 获取 get(int index) 4 删除 remove(int index) , remove(Objec ...
- Java集合类源码解析:Vector
[学习笔记]转载 Java集合类源码解析:Vector 引言 之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector.为什么说是它兄弟呢?因为从容器的构造来说,Vec ...
- Java集合类源码解析:HashMap (基于JDK1.8)
目录 前言 HashMap的数据结构 深入源码 两个参数 成员变量 四个构造方法 插入数据的方法:put() 哈希函数:hash() 动态扩容:resize() 节点树化.红黑树的拆分 节点树化 红黑 ...
- 从源码解析LinkedList集合
上篇文章我们介绍了ArrayList类的基本的使用及其内部的一些方法的实现原理,但是这种集合类型虽然可以随机访问数据,但是如果需要删除中间的元素就需要移动一半的元素的位置,效率低下.并且它内 ...
- Java集合类源码解析:ArrayList
目录 前言 源码解析 基本成员变量 添加元素 查询元素 修改元素 删除元素 为什么用 "transient" 修饰数组变量 总结 前言 今天学习一个Java集合类使用最多的类 Ar ...
- Java集合类源码解析:AbstractMap
目录 引言 源码解析 抽象函数entrySet() 两个集合视图 操作方法 两个子类 参考: 引言 今天学习一个Java集合的一个抽象类 AbstractMap ,AbstractMap 是Map接口 ...
- Java集合类源码解析:LinkedHashMap
前言 今天继续学习关于Map家族的另一个类 LinkedHashMap .先说明一下,LinkedHashMap 是继承于 HashMap 的,所以本文只针对 LinkedHashMap 的特性学习, ...
随机推荐
- Springmvc配置时间日期转换
1.局部日期转换 @Controller public class ProductController{ @RequestMapping(value="/test/springmvc.do& ...
- tomcat端口被占用 实际上却查询不到此端口
参考 http://www.cnblogs.com/jieliujas/p/9413064.html 1.打开PCHunter,在进程选项卡下面可以找到无法结束的进程,右键--强制结束,失败(这儿效果 ...
- Oracle 存储过程例子返回记录集
转载:https://www.cnblogs.com/mikalshao/articles/1454134.html Oracle 不支持批量查询,因此无法从一个命令返回多个结果集.使用存储过程时,返 ...
- web.config中连接字符串的读写和加密解密
转载:https://www.cnblogs.com/shuai/articles/2248703.html 1.先来看看如何在web.config中写入数据库连接字符串.打开web.config文件 ...
- c++ 读入优化、输出优化模板
0. 在有些输入数据很多的变态题中,scanf会大大拖慢程序的时间,cin就更慢了,所以就出现了读入优化.其原理就是一个一个字符的读入,输出优化同理,主要使用getchar,putchar函数. 1. ...
- centos 6 下KVM 安装学习之旅
一.虚拟化介绍 虚拟化是云计算的基础.简单的说,虚拟化使得在一台物理的服务器上可以跑多台虚拟机,虚拟机共享物理机的 CPU.内存.IO 硬件资源,但逻辑上虚拟机之间是相互隔离的. 物理机我们一般 ...
- HDFS 总结
HDFS是一个分布式文件存储系统 Client 提交读写请求(拆分blocksize) NameNode 全局把控(知道blocksize的地址) dataNode 存储数据(将数据存储进去,且以P ...
- phpStudy安装教程
1.在phpStudy官网下载安装包(http://phpstudy.php.cn/)2.解压安装后,若提示没有“VC9.VC11.VC14运行库,注意是X86 32位”,则在phpStudy下载对应 ...
- 204. Count Primes (Integer)
Count the number of prime numbers less than a non-negative number, n. 思路:寻找质数的方法 class Solution { pu ...
- React 入门实例教程【转】
Any day will do. 哪一天都行 Are you kidding? 你在开玩笑吧! Congratulations! 祝贺你! I don’t mean it. 我不是故意的. 原文作者: ...