1. LinkedList简介

  LinkedList是一种可以在任何位置进行高效地插入和移除操作的有序序列,它是基于双向链表实现的。因为它实现了Deque接口,所以也是双端队列的一种实现。

2.LinkedList继承关系

  LinkedList继承自AbstractSequentialList,实现了List、Deque、Cloneable、java.io.Serializable接口。

  1. AbstractSequentialList继承自AbstractList,是List的简化版实现,只支持按次序访问,不支持随机访问。可以被当做堆栈,队列来进行操作。

  2. List定义了列表必实现的一些方法,如添加、删除、读取、插入、获取大小等。

  3. Deque定义了双端队列必实现的一些方法

  4. 实现了Cloneable接口:可以调用Object.clone方法返回该对象的浅拷贝。

  5. 实现了 java.io.Serializable 接口:可以启用其序列化功能,能通过序列化去传输。

3. LinkedList实现

1. 核心属性

  LinkedList底层存储是Node节点,每个节点包含了当前元素、上一个Node节点和下一个Node节点,这种双向链表的结构的好处是插入和删除都比较快,但是查找则比较慢。

  从下面的属性可以看出,我们只知道链表首节点和尾节点的Node以及Node节点的个数,对于中间的Node则需要依次迭代才能依次获取,所以查询是很慢的。

    //实现Serilizable接口时,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
transient int size = 0;
//指向首节点
transient Node<E> first;
//指向最后一个节点
transient Node<E> last; //内部类,定义了LinkedList内部链表的节点属性
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;
}
}

2. 构造函数

    public LinkedList() {
} public LinkedList(Collection<? extends E> c) {
// 调用无参构造函数
this();
// 添加集合中所有的元素
addAll(c);
}

3. 核心方法

  LinkedList在头部和尾部对数据进行操作的时候相对来说效率会快一点,但是中间插入数据的时候,需要进行遍历,所以当数据量越大时效率越低。

  开头插入,LinkedList比ArrayList快

  中间插入,LinkedList比ArrayList慢

  尾部插入,当数据量越来越大时,ArrayList比LinkedList快:当数据量大时,ArrayList每次扩容都能得到很大的新空间,解决了前期频繁扩容的劣势,而LinkedList虽然有尾指针,但是每次add都要将对象new成一个Node(而ArrayList直接数组对应位置元素赋值)

   //将节点值为e的节点作为首节点
private void linkFirst(E e) {
final Node<E> f = first;
//构建一个prev值为null,next为f,节点值为e的节点
final Node<E> newNode = new Node<>(null, e, f);
//将newNode作为首节点
first = newNode;
//如果newNode后面没有节点就将newNode作为最后一个节点
if (f == null)
last = newNode;
//否则就将newNode赋给其prev
else
f.prev = newNode;
//列表长度加一
size++;
modCount++;
}
//将节点值为e的节点作为最后一个节点
void linkLast(E e) {
final Node<E> l = last;
//构建一个prev值为l,next为null,节点值为e的节点
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
//在非空节点succ之前插入节点e
void linkBefore(E e, Node<E> succ) {
final Node<E> pred = succ.prev;
//将succ前面的节点和succ作为其prev和next
final Node<E> newNode = new Node<>(pred, e, succ);
//然后将newNode作为succ的prev
succ.prev = newNode;
//如果原来succ是首节点,则将newNode设置为首节点
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
//释放非空的首节点f
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节点后面的节点设为首节点
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
//释放非空的尾节点l
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; //x后面的节点
final Node<E> prev = x.prev; //x前面的节点 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;
}
//返回列表首节点元素值
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
//返列表尾节点元素值
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
//移除首节点
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
//删除尾节点
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
//在列表首部插入节点e
public void addFirst(E e) {
linkFirst(e);
}
//在列表尾部插入节点e
public void addLast(E e) {
linkLast(e);
}
//判断列表中是否包含有元素o
public boolean contains(Object o) {
return indexOf(o) != -1;
}
//返回列表长度大小
public int size() {
return size;
}
//在列表尾部插入元素
public boolean add(E e) {
linkLast(e);
return true;
}
//删除元素为o的节点
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;
}
//将集合c中所有元素添加到列表的尾部
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
//从指定的位置index开始,将集合c中的元素插入到列表中
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 { //否则,找到index所在的节点
succ = node(index);
pred = succ.prev;
}
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
//删除列表中所有节点
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++;
}
//获取指定索引位置节点的元素值
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
//替换指定索引位置节点的元素值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
//在指定索引位置之前插入元素e
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//删除指定位置的元素
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
  //返回指定索引位置的节点
  Node<E> node(int index) {
    //此处是一个小技巧,当index<size/2时,从列表前半部分开始,否则从后半部分开始
    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;
    }
  }   //返回列表中第一次出现o的位置,若不存在则返回-1
  public int indexOf(Object o) {
    int index = 0;
    if (o == null) {
      for (Node<E> x = first; x != null; x = x.next) {
        if (x.item == null)
        return index;
        index++;
      }
    } else {
      for (Node<E> x = first; x != null; x = x.next) {
        if (o.equals(x.item))
          return index;
        index++;
      }
    }
  return -1;
  }
  //逆向搜索,返回第一出现o的位置,不存在则返回-1
  public int lastIndexOf(Object o) {
    int index = size;
    if (o == null) {
      for (Node<E> x = last; x != null; x = x.prev) {
        index--;
        if (x.item == null)
          return index;
      }
    } else {
      for (Node<E> x = last; x != null; x = x.prev) {
        index--;
        if (o.equals(x.item))
          return index;
      }
    }
    return -1;
  }

 

学习JDK1.8集合源码之--LinkedList的更多相关文章

  1. 【JDK1.8】JDK1.8集合源码阅读——LinkedList

    一.前言 这次我们来看一下常见的List中的第二个--LinkedList,在前面分析ArrayList的时候,我们提到,LinkedList是链表的结构,其实它跟我们在分析map的时候讲到的Link ...

  2. 学习JDK1.8集合源码之--ArrayList

    参考文档: https://cloud.tencent.com/developer/article/1145014 https://segmentfault.com/a/119000001857894 ...

  3. 学习JDK1.8集合源码之--LinkedHashSet

    1. LinkedHashSet简介 LinkedHashSet继承自HashSet,故拥有HashSet的全部API,LinkedHashSet内部实现简单,核心参数和方法都继承自HashSet,只 ...

  4. 学习JDK1.8集合源码之--WeakHashMap

    1. WeakHashMap简介 WeakHashMap继承自AbstractMap,实现了Map接口. 和HashMap一样,WeakHashMap也是一种以key-value键值对的形式进行数据的 ...

  5. 学习JDK1.8集合源码之--HashMap

    1. HashMap简介 HashMap是一种key-value结构存储数据的集合,是map集合的经典哈希实现. HashMap允许存储null键和null值,但null键最多只能有一个(HashSe ...

  6. 学习JDK1.8集合源码之--ArrayDeque

    1. ArrayDeque简介 ArrayDeque是基于数组实现的一种双端队列,既可以当成普通的队列用(先进先出),也可以当成栈来用(后进先出),故ArrayDeque完全可以代替Stack,Arr ...

  7. 学习JDK1.8集合源码之--HashSet

    1. HashSet简介 HashSet是一个不可重复的无序集合,底层由HashMap实现存储,故HashSet是非线程安全的,由于HashSet使用HashMap的Key来存储元素,而HashMap ...

  8. 学习JDK1.8集合源码之--Stack

    1. Stack简介 Stack是集合中对数据结构栈的一种实现,栈的原则是先进先后出,与队列相反(先进先出).Stack是继承自Vector的,意味着它也是由数组实现的线程安全的,不考虑线程安全的情况 ...

  9. 学习JDK1.8集合源码之--Vector

    1. Vector简介 Vector是JDK1.0版本就推出的一个类,和ArrayList一样,继承自AbstractList,实现了List.RandomAccess.Cloneable.java. ...

随机推荐

  1. CSS奇数、偶数、指定数样式

    原文: https://blog.csdn.net/wangjia200913/article/details/49615325 语法    :nth-child(an+b) 第一种:简单数字序号写法 ...

  2. Odoo中使用的部分表名及用途

    res_users 用户res_groups 用户组(角色)res_lang 语言res_partner 供应商/客户/联系人res_font 字体res_company 公司res_bank 银行r ...

  3. BZOJ3907 网格 卡特兰数

    题目描述 某城市的街道呈网格状,左下角坐标为A(0, 0),右上角坐标为B(n, m),其中n >= m. 现在从A(0, 0)点出发,只能沿着街道向正右方或者正上方行走,且不能经过图示中直线左 ...

  4. 第四章 Odoo 12 开发之模块继承

    Odoo 的一个强大功能是无需直接修改底层对象就可以添加功能.这是通过其继承机制来实现的,采取在已有对象之上修改层来完成.这种修改可以在不同层上进行-模型层.视图层和业务逻辑层.我们创建新的模块来做出 ...

  5. 搭建Angular环境

    一.安装nodejs 登录nodejs官网,下载对应系统版本:安装,只要一直下一步即可. 在nodejs中自带了npm,不需要独立安装npm. 输入node -v /npm -v  查看node和np ...

  6. poj 3263

    传送门 解题思路 如果x与y互相看见,那么他们一定比之间的高,所以给他们之间的高度-1,最后得到的答案是所有牛的高度+h,之间-1会T,用差分数组或线段树维护即可. 代码 #include<io ...

  7. Django-rest Framework(四)

    序列化模块时rest-framework的很重要的组成部分 rest-framework序列化模块(核心) 一. 为什么要使用序列化组件? ​ 后台的数据多以后台的对象存在,经过序列化后,就可以格式化 ...

  8. JasperReports报表变量13

    报表变量是建立在报表表达式之上的特殊对象.报表变量简化以下任务: 报表,其中大量使用在整个报告模板表达式.这些表达式可以通过使用报表变量只能声明一次. 计数,求和,平均,最低,最高,方差等:报表变量可 ...

  9. Hadoop集群中有哪些节点类型

  10. HDU3374 字符串最大最小表示法模板

    一开始没太看懂什么意思,拿笔反复推了一遍才大概知道最大最小表示法是怎么求的,感觉太神奇了... #include <iostream> #include <cstdio> #i ...