一.LinkedList的内部数据结构

  LinkedList底层是一个链表的数据结构,采用的是双向链表,基本的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;
}
}

二.LinkedList的结点的常用操作

  在LinkedList实现List接口的一系列方法的时候,底层是通过一系列结点操作,完成对于LinkedList的方法的实现,操作代码如下:

    /**
* 将一个元素链接到链表的开头
*/
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
} /**
* 将元素e链接到链表的末端
*/
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++;
} /**
* 将一个元素链接到指定结点的前面
*/
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
} /**
* 将一个first结点解除关联
*/
private E unlinkFirst(Node<E> f) {
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
} /**
* 将一个last结点解除关联
*/
private E unlinkLast(Node<E> l) {
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
} /**
* 将一个结点x解除链接
*/
E unlink(Node<E> x) {
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;
}

三.LinkedList的addAll方法

  插入一个Collection类型的元素的时候,需要先将Collection元素转化为数组类型的元素,然后对于数组中的每一个元素进行遍历,建立一系列结点,并将结点相互连接,然后与原来的结点相互连接.

public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false; Node<E> pred, succ;
if (index == size) { //表示在链表末尾添加
succ = null;
pred = last;
} else { //在链表中间添加
succ = node(index);//获取在当前索引位置的元素
pred = succ.prev;//pred--记录当前索引位置的元素的前面的一个元素
} for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null); //在当前索引位置的元素前面添加元素
if (pred == null) //前面没有元素,说明插入的节点是链表的第一个元素
first = newNode;
else //前面节点的next指向当前节点
pred.next = newNode;
pred = newNode; //pred指向当前节点为下一次赋值做准备
} if (succ == null) { //插入前,索引处没有元素
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
} size += numNew;
modCount++;
return true;
}

四.remove操作

  remove操作通过对于链表结点进行遍历,如果结点的元素等于参数的元素,则调用unlink方法,将结点的关系解除.

public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == 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;
}

五.clear方法

  通过对于链表的所有的元素进行遍历,并且将遍历到的元素的所有属性设为null,交给垃圾回收器处理.

public void clear() {
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}

六.get方法

  get方法是LinkedList获取某一索引处的元素的方法,由于链表的数据结构查询比较慢,因此通常不推荐对于LinkedList类型的数据结构调用一系列get方法.但是LinkedList数据结构本身对于get方法进行了优化,当索引大于中间索引的时候,从最后一个元素开始查询.当索引小于中间索引的时候,从第一个元素开始查询.

 public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int 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;
}
}

Java源码初学_LinkedList的更多相关文章

  1. Java源码初学_AbstractList&AbstractCollection

    一.AbstractCollection抽象类:(提供了Collection接口的骨干实现,以减少实现接口所需要的工作) 1.contains方法 contains方法,通过迭代器对于列表的每一个元素 ...

  2. Java源码初学_HashSet&LinkedHashSet

    一.概述 HashSet是建立在HashMap的基础上的,其内部存在指向一个HashMap对象的引用,操作HashSet实际上就是操作HashMap,而HashMap中所有键的值都指向一个叫做Dumm ...

  3. Java源码初学_LinkedHashMap

    一.概述: LinkedHashMap是HashMap的子类,它的基本操作与HashMap相同,与之不同的是,它可以实现按照插入顺序进行排序.也可以通过在构造函数中指定参数,按照访问顺序排序(Link ...

  4. Java源码初学_HashMap

    一.概念 HashMap的实例有两个参数影响其性能:初始容量和加载因子.容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量.加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度.当哈希表 ...

  5. Java源码初学_ArrayList

    一.ArrayList的构造器和构造方法 在ArrayList中定义了两个空数组,分别对应当指定默认构造方法时候,指向的数组已经给定容量,但是容量等于0的时候,指向的数组.此外在构造函数中传入Coll ...

  6. 如何阅读Java源码 阅读java的真实体会

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动. 源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心.   说到技术基础,我打个比 ...

  7. Android反编译(一)之反编译JAVA源码

    Android反编译(一) 之反编译JAVA源码 [目录] 1.工具 2.反编译步骤 3.实例 4.装X技巧 1.工具 1).dex反编译JAR工具  dex2jar   http://code.go ...

  8. 如何阅读Java源码

    刚才在论坛不经意间,看到有关源码阅读的帖子.回想自己前几年,阅读源码那种兴奋和成就感(1),不禁又有一种激动.源码阅读,我觉得最核心有三点:技术基础+强烈的求知欲+耐心. 说到技术基础,我打个比方吧, ...

  9. Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库

    http://www.iteye.com/topic/1113732 原则网址 Java源码初接触 如果你进行过一年左右的开发,喜欢用eclipse的debug功能.好了,你现在就有阅读源码的技术基础 ...

随机推荐

  1. RabbitMQ 基本概念介绍-----转载

    1. 介绍 RabbitMQ是一个由erlang开发的基于AMQP(Advanced Message Queue )协议的开源实现.用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面都非 ...

  2. 发现一个jq的问题

    用jq对checkbox的checked属性进行操作时,使用$(‘#id’).attr(‘checked’, true);竟然无效,改成$(‘#id’).prop(‘checked’, true);才 ...

  3. C++陷阱之慎用string类

    我们知道,string类为我们提供了很多的便利,我们用string类能方便的做字符串的各种操作,避免了我们直接操作char指针而产生的一些繁琐的操作,和内存泄露的可能性,可是string类也是有陷阱的 ...

  4. Codeforces Round #336 Marbles

    E. Marbles time limit per test:  2 seconds memory limit per test:  256 megabytes input:  standard in ...

  5. Number Sequence 分类: HDU 2015-06-19 20:54 10人阅读 评论(0) 收藏

    Number Sequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tot ...

  6. Mybatis like 模糊查询问题

    1.mysql:LIKE CONCAT('%',#{empname},'%' ) 或者 LIKE CONCAT('%',‘${empname}’,'%' ) 2.oracle:LIKE '%'||#{ ...

  7. 查看linux发行版本、内核版本命令

    查看linux发行版本: $lsb_release -a 查看linux内核版本: $cat /proc/version 或 $uname -a

  8. 【Linux】vi(vim)起步学起来有些困难,一步一步温习

    以Tomcat的配置文件service.xml为例,记录.学习vi的最常用操作. > 什么是vi or vim? [nicchagil@localhost bak]$ man vi VIM() ...

  9. _in、_out。。。

    _in 输入参数_out 输出参数_opt 参数是可选的,就是可以为NULL_ecount 所指向的缓存的元素个素 也就是括号里的数字

  10. 复旦大学2014--2015学年第一学期(14级)高等代数I期末考试第七大题解答

    七.(本题10分)  设 \(V\) 为数域 \(\mathbb{K}\) 上的 \(n\) 维线性空间, \(S=\{v_1,v_2,\cdots,v_m\}\) 为 \(V\) 中的向量组, 定义 ...