- 浏览: 197716 次
- 性别:
- 来自: 南京
文章分类
最新评论
-
hahalzb:
请问文件解压缩的密码是什么呀
JMS简介与ActiveMQ实战 -
ershimengx:
JMS&ActiveMQ实战(JMS+ActiveMQ ...
JMS简介与ActiveMQ实战 -
lgh1992314:
zenghuiss 写道我书读的少,你不要蒙我哦。。。over ...
Java method invoke的指令简介 -
P00116:
...
JMS简介与ActiveMQ实战 -
风会停息丶:
你好,下载完成后解压密码是多少,跟网盘下载密码一样吗
JMS简介与ActiveMQ实战
上篇文章浅析了ArrayList的源码相关内容!这篇文章将介绍LinkedList相关的内容!
二. LinkedList
先来看看LinkedList的类结构!
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
1. 几个重要的成员变量
private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;//LinkedList的长度 ,初始化为0
这里先来说一下header这个变量,这个很重要哦!
首先看一下Entry是个什么东西!
private static class Entry<E> { E element; Entry<E> next; Entry<E> previous; Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; } }
对的,Entry就是LinkedList的一个内部静态类!我们知道LinkedList的内部数据结构采用的链式存储方式,链式存储决定了它插入的速度会相对会快,而索引的速度慢!链式存储最主要的有三个元素:当前元素、前一个元素地址、后一个元素地址。
Entry类中element表示当前元素; next表示后一个元素;previous表示前一个元素;这样的话一个链式的存储的模型就有了。
2. 两个构造函数
/** * Constructs an empty list. */ public LinkedList() { header.next = header.previous = header; }
无参构造函数初始化的时候header的前一个、后一个均指向本身。
/** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
根据已有的Collection初始化LinkedList,我们来看一个addAll(int index, Collection<? extends E> c)这个方法(addAll(Collection<? extends E> c)本身也是调用的此方法,其中index的参数值为size而已)。
/** * Inserts all of the elements in the specified collection into this * list, starting at the specified position. Shifts the element * currently at that position (if any) and any subsequent elements to * the right (increases their indices). The new elements will appear * in the list in the order that they are returned by the * specified collection's iterator. * * @param index index at which to insert the first element * from the specified collection * @param c collection containing elements to be added to this list * @return <tt>true</tt> if this list changed as a result of the call * @throws IndexOutOfBoundsException {@inheritDoc} * @throws NullPointerException if the specified collection is null */ public boolean addAll(int index, Collection<? extends E> c) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); Object[] a = c.toArray(); int numNew = a.length; if (numNew == 0) return false; modCount++; Entry<E> successor = (index == size ? header : entry(index)); Entry<E> predecessor = successor.previous; for (int i = 0; i < numNew; i++) { Entry<E> e = new Entry<E>((E)a[i], successor, predecessor); predecessor.next = e; predecessor = e; } successor.previous = predecessor; size += numNew; return true; }
前面的我就不说了,都是一些预判断。我们来分析下下面这段代码的含义
Entry<E> successor = (index == size ? header : entry(index)); Entry<E> predecessor = successor.previous;
粗略的看一个successor和predecessor 英文含义分别表示为后继者和前辈;对呀,我们想啊,LinkedList本身是一个链式存储结构,你要将一些内容插入进来,首先必须要在链上找到一个入口,然后将此入口掐断,接着将你插入进来的内容放进去,最后再将这个链给接起来,你要将链给接起来要接对啊,不能接错地方啊!successor、predecessor就是为了将链接对所用,分别指向链断裂后,后一段和前一段的链接地址。
我们来看下面这两张图:
图一
图二
上面我描述的过程就类似于从图一到图二的过程。
初步感性的分析玩之后我们来详细分析一下!
这里做了一个判断:如果当前插入的index的值等于size则返回header,否则返回entry(index);
1. index == size时,其实就是插入到链尾处,因为链尾处的元素的next比较特殊,它指向了链首header。
2. index != size时,我们先来看一下entry(int index)这个方法的源码:
/** * Returns the indexed entry. */ private Entry<E> entry(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); Entry<E> e = header; if (index < (size >> 1)) { for (int i = 0; i <= index; i++) e = e.next; } else { for (int i = size; i > index; i--) e = e.previous; } return e; }
其实就是找到找到索引值为index的Entry,判断index值大小是否已经超过了size值的一半,如果没超过就从链表头部开始遍历,否则从链表尾部开始遍历。
ps:看得出来,按索引找个Entry这么麻烦,真慢,不像ArrayList来得那么直接。这就是为什么LinkedList索引慢的原因,存储结构决定的,基因问题,呵呵。
3. Entry<E> predecessor = successor.previous; 鉴于上面的分析,这句也就不难理解了。
4.
for (int i = 0; i < numNew; i++) { Entry<E> e = new Entry<E>((E)a[i], successor, predecessor); predecessor.next = e; predecessor = e; }
这段代码就是将初始化的Collection数据一个一个链接上去。
successor.previous = predecessor; size += numNew;
最后将这个链给接回去,形成了一个闭环链! LinkedList的大小也要增加一下嘛!
3. 几个常用方法浅析
/** * Inserts the specified element at the specified position in this list. * Shifts the element currently at that position (if any) and any * subsequent elements to the right (adds one to their indices). * * @param index index at which the specified element is to be inserted * @param element element to be inserted * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { addBefore(element, (index == size ? header : entry(index))); }
有些代码是不是很熟悉啊?呵呵,还是看内部的addBefore(E e, Entry<E> entry)方法吧。
private Entry<E> addBefore(E e, Entry<E> entry) { Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; size++; modCount++; return newEntry; }
这个还用我说吗? 是不是比在构造方法里面的要简单得多啊。
/** * Returns the element at the specified position in this list. * * @param index index of the element to return * @return the element at the specified position in this list * @throws IndexOutOfBoundsException {@inheritDoc} */ public E get(int index) { return entry(index).element; }
获取指定索引值index的元素,呵呵,不解释了!
/** * Returns the first element in this list. * * @return the first element in this list * @throws NoSuchElementException if this list is empty */ public E getFirst() { if (size == 0) throw new NoSuchElementException(); return header.next.element; } /** * Returns the last element in this list. * * @return the last element in this list * @throws NoSuchElementException if this list is empty */ public E getLast() { if (size == 0) throw new NoSuchElementException(); return header.previous.element; }
分别为获取第一个和最后一个元素的值,也很简单啊,第一个元素就是header的next的element的值,最后一个元素就是header的previous的element的值。
ps:真实的内部情况是这样的,整个链表的内容是包含header的Entry和LinkedList存储的所有Entry两个部分共同组成的。
/** * Returns the index of the first occurrence of the specified element * in this list, or -1 if this list does not contain the element. * More formally, returns the lowest index <tt>i</tt> such that * <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, * or -1 if there is no such index. * * @param o element to search for * @return the index of the first occurrence of the specified element in * this list, or -1 if this list does not contain the element */ public int indexOf(Object o) { int index = 0; if (o == null) { for (Entry e = header.next; e != header; e = e.next) { if (e.element == null) return index; index++; } } else { for (Entry e = header.next; e != header; e = e.next) { if (o.equals(e.element)) return index; index++; } } return -1; }
返回第一个包含对象o的索引值。也很简单吧,对吧!
private E remove(Entry<E> e) { if (e == header) throw new NoSuchElementException(); E result = e.element; e.previous.next = e.next; e.next.previous = e.previous; e.next = e.previous = null; e.element = null; size--; modCount++; return result; }
这是一个private方法,就是删除链表中的一个Entry,思路如下:将要移除的对象e的previous的next指向e的next,对象e的next的previous指向e的previous,就是将链表的一个节点删掉,在将这个链表接起来。
/** * Replaces the element at the specified position in this list with the * specified element. * * @param index index of the element to replace * @param element element to be stored at the specified position * @return the element previously at the specified position * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { Entry<E> e = entry(index); E oldVal = e.element; e.element = element; return oldVal; }
这个更简单,就是替换索引index的Entry的element的值。
好吧,基本常用的方法也都分析完了,重点已经照顾到了,其他的就不再累述了。
这里就简单描述一下Vector吧!
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
Vector用得并不多,它和ArrayList很相似,但是它本身是线程安全的,看源码就能够看得出来,很多方法都是synchronized,但是在jdk1.6上就已经有java.util.concurrent了,对于多线程编程的话,Vector的用武之地也很少了,这里就不再讲了!
ps:附件中我上传了一个比较不错的Data Structure Visualzation工具,是一个jar包运行java -jar 执行。对于分析与理解数据结构方面的问题相当有帮助。
发表评论
-
Java class file format
2011-08-29 17:26 0A class file consists of a s ... -
自己动手写写:HashSet、LinkedHashSet源码浅析
2011-08-12 14:40 2019这篇文章我只是作为一个简要的分析。 首先可以看看之前写 ... -
自己动手写写:LinkedHashMap源码浅析
2011-08-11 10:31 4245此系列文章中,上一篇是关于HashMap的源码剖析,这篇文章将 ... -
自己动手写写:HashMap源码浅析
2011-08-04 13:50 4553虽说论坛中有很多关于HashMap源码的分析,并且都是分析得很 ... -
自己动手写写:ArrayList源码浅析
2011-08-02 17:29 3473了解你所使用的东西,最直接有效的方式莫过于源码切入的方式! ...
相关推荐
接下来,我们将通过JDK 7.0的源码,深入探讨LinkedList的底层实现原理。 首先,LinkedList实现了List接口,因此它是一个有序列表。它还实现了Deque接口,这意味着LinkedList支持双端队列的操作。除了这些接口之外,...
《深入Java8的集合2:LinkedList的实现原理》 LinkedList是Java编程语言中实现List接口的一种数据结构,它采用双链表的方式存储元素。本文将深入解析LinkedList的内部机制,帮助开发者理解其工作原理。 首先,...
《Jdk1.6 Collections Framework源码解析(2)-LinkedList》 LinkedList是Java集合框架中的一个重要的类,它是List接口的实现,同时继承了AbstractSequentialList,并实现了Deque接口。LinkedList是一种双链表结构,...
### LinkedList部分源码解析 #### 一、简介 `LinkedList`是Java集合框架的一个重要组成部分,它基于双向链表实现,既支持`List`接口也实现了`Deque`接口,因此可以作为列表、栈或者队列使用。双向链表的每个节点...
·企业级笔试面试题目深入源码级讲解,拒绝死记硬背 4.代码量更大、案例更丰富、更贴近实战: ·Java语言基础阶段:12720行代码,Java语言高级阶段:11684行代码 ·课堂实战项目3套,课后实战项目2套 ·近百道企业...
LinkedList源码
在Java编程语言中,ArrayList、Vector和LinkedList是三种常见的动态数组实现,它们都属于集合框架中的List接口。这里我们将深入探讨这三种数据结构的源码,理解它们的内部实现、性能特性和适用场景。 首先,...
LinkedList是Java中的一个类,位于java.util包下,它是List接口的一个实现,主要用于存储动态的、有序的数据集合。与数组不同,链表的元素不需要在内存中连续存储,这使得在链表中插入和删除元素具有较高的效率。 ...
《深入理解Java中的LinkedList》 在Java编程语言中,LinkedList是一种重要的数据结构,它属于集合框架的一部分,位于java.util包下。LinkedList是一个双向链表,它不仅提供了存储元素的功能,还支持快速地在链表的...
《LinkedList源码学习分析》 LinkedList作为Java集合框架中的一员,是基于链表数据结构实现的线程不安全容器。本文将深入探讨LinkedList的实现原理、核心方法的代码实现,并对比ArrayList,理解其特性和使用场景。 ...
LinkedList源码解析 LinkedList是Java中的一种链表实现,它的底层是一个环形双向链表。在 LinkedList 中,节点之间通过引用相互连接,形成一个链表结构。LinkedList 提供了多种方法来操作链表,包括添加、删除、...
在JavaScript编程中,LinkedList是一种常见的数据结构,它与数组不同,具有特定的性能优势,尤其在插入和删除操作上。本篇文章将深入探讨JavaScript中的LinkedList及其应用。 LinkedList是由一系列节点构成的链式...
《LinkedList源码解析》 LinkedList是Java集合框架中的一员,它是AbstractSequentialList的子类,同时也实现了List、Deque和Cloneable、Serializable接口。LinkedList作为双向链表,支持快速的添加、删除元素,尤其...
Java集合框架中的LinkedList是一个强大的数据结构,因为它同时实现了List接口和Deque接口,使其既具备顺序容器的功能,又能作为队列和栈使用。LinkedList基于双向链表实现,这意味着它支持高效地在两端添加和删除...
`linkedList`标题暗示我们将探讨的是与链表相关的操作,而描述中提到的“在LinkedlIst上的操作”进一步确认了这一点。在这个C语言实现的链表项目中,`linkedList-master`可能是源代码文件夹,包含了链表操作的相关...
【ArrayList、LinkedList、Vector对比分析】 1. **List概述** List接口是Java集合框架中的重要组成部分,它是一个有序的集合,允许重复元素,并且保持插入顺序。List接口的实现类主要有ArrayList、LinkedList和...
《ArrayList与LinkedList源码解析》 在Java编程中,ArrayList和LinkedList是两种常见的动态数组,它们都是Java集合框架的一部分,提供了对元素存储和操作的功能。本篇将深入探讨ArrayList和LinkedList的内部实现...
第十五讲和第十六讲可能涵盖Java的集合框架,包括ArrayList、LinkedList、HashSet、HashMap等数据结构的源码分析。集合框架是Java库的重要组成部分,提供了存储和操作对象的高效工具。通过对这些类的源码学习,我们...
### LinkedList源码分析 #### 一、概述 `LinkedList` 是 Java 集合框架中的一个重要组成部分,它基于双向链表实现。与基于数组的 `ArrayList` 相比,`LinkedList` 在插入和删除操作上更为高效,因为它只需要改变...
LinkedList是Java集合框架中的一种数据结构,主要用于存储有序的元素序列。它实现了List接口,这意味着它支持添加、删除、修改和遍历元素等操作。在本文中,我们将深入探讨LinkedList如何实现List接口的一些主要方法...