一.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. 浅谈mysql mvcc

    以下为个人理解,如有错误,还望指正!! mysql的大多数事务型存储引擎实现的都不是简单的行级锁,基于提升并发性能的考虑,他们一般都同时实现了多版本并发控制,可以认为MVCC是行级锁的一个变种,但是它 ...

  2. Linux上部署Tomcat(包括JAVA环境的配置)

    一. 用FTP工具,把apache-tomcat-7.0.64.tar.gz,jdk-7u79-linux-x64.tar.gz 上传到目录/home/zwl/Tomcat/命令下 因为Tomcat运 ...

  3. jqeury之轮播图

    $(document).ready(function(){ var sWidth = $('#pic1').width(); var len = $('#pic1 .sildebar li').len ...

  4. Pie(二分POJ3122)

    Pie Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12985   Accepted: 4490   Special Ju ...

  5. Stars(树状数组或线段树)

    Stars Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 37323 Accepted: 16278 Description A ...

  6. 提高 Linux 上 socket 性能

      http://www.cnblogs.com/luxf/archive/2010/06/13/1757662.html 基于Linux的Socket网络编程的性能优化   1 引言    随着In ...

  7. 内存恶鬼drawRect

    标题有点吓人,但是对于drawRect的评价倒是一点都不过分.在平日的开发中,随意覆盖drawRect方法,稍有不慎就会让你的程序内存暴增.下面我们来看一个例子. 去年的某天午后,北京的雾霾依旧像现在 ...

  8. CF 113C

    求区间 [l,r]   满足 素数 = a^2+b^2    a b为任意整数 打素数表,如何证明  此时的素数满足 %4==1 #include<iostream> #include&l ...

  9. mysql分库分表

    1.分库分表 很明显,一个主表(也就是很重要的表,例如用户表)无限制的增长势必严重影响性能,分库与分表是一个很不错的解决途径,也就是性能优化途径,现在的案例是我们有一个1000多万条记录的用户表mem ...

  10. linux系统中如何查看日志 (常用命令2)

    cat tail -f 日 志 文 件 说 明 /var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日志之一 /var/log/secure 与安全相关 ...