List接口实现类-ArrayList、Vector、LinkedList集合深入学习以及源代码解析
学习List接口实现类 ArrayList Vector LinkedList
List接口的实现类中最经常使用最重要的就是这三个:ArrayList、Vector、LinkedList。
JDK中这三个类的定义:
1、ArrayList<E>:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer.
*/
private transient Object[] elementData;
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
2、 Vector<E>:
public class Vector<E>extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/**
* The array buffer into which the components of the vector are
* stored. The capacity of the vector is the length of this array buffer,
* and is at least large enough to contain all the vector's elements.
*
* <p>Any array elements following the last element in the Vector are null.
*
* @serial
*/
protected Object[] elementData;
3、LinkedList<E>:
public class LinkedList<E>extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{ // 在序列化这个对象的时候这个变量不会被这样序列化
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
4、从这三个类定义就能够看出一些信息:
(1)、三个都直接实现了AbstractList这个抽象类
(2)、ArrayList和Vector都实现了RandomAccess接口。而LinkedList没有。这是什么意思呢?
在JDK 中,RandomAccess接口是一个空接口,所以它没有实际意义。就是一个标记,
标记这个类支持高速随机訪问,所以,arrayList和 vector是支持随机訪问的,可是LinkedList不支持持
(3)、serializbale接口表明他们都支持序列化。
5、以下具体说说List的这三个实现:
(1)、 查看实现源代码会发现这三个里面,ArrayList和Vector使用了数组的实现,相当于封装了对数组的操作。这也正是他们可以支持高速随机訪问的原因,多说一句,JDK中全部基于数组实现的数据结构都可以支持高速随机訪问。
ArrayList和Vector的实现上差点儿都使用了同样的算法,他们的主要差别就是ArrayList没有对不论什么一个方法做同步处理,所以不是线程安全的;而Vector中大部分方法都做了线程同步所以是线程安全的。
(2)、LinkedList使用的是双向循环链表的数据结构。因为是基于链表的。所以无法法实现随机訪问的,仅仅能顺序訪问,这也正是它没有实现RandomAccess接口的原因。
(3)、因为ArrayList、Vector和LinkedList所採用的数据结构不同。注定他们适用的是全然不同的场景。
通过阅读这几个类的源代码,我们能够看到他们实现的不同。
ArrayList和Vector基本一样,我们就用ArrayList和LinkedList做对照。
在末尾添加一个元素
6、ArrayList中的add方法实现例如以下:
/**
* Appends the specified element to the end of this list.
*将元素加入到list的最后
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
// 推断容量
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
这种方法做两件事情,首先确保数组空间足够大。然后在数组末尾添加元素而且通过后++使得完毕size+1
从这个代码能够看出,假设数组空间足够大,那么仅仅是数组的add操作就是O(1)的性能,很高效。
7、在看看ensureCapacityInternal这种方法的实现:
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code。假设空间不够则扩容也就是又一次创建一个Object[]对象
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
8、grow(int minCapacity)方法创建数组并将原来的数据复制到新数组中
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 使用移位运算,提高效率
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
能够看出。假设数组空间不够,那么这种方法就会做数组扩容和数组复制操作,看上面,JDK利用移位运算符进行扩容计算,>>1右移一位表示除2,所以newCapacity就是扩容为原来的1.5倍。
9、这里的代码都是JDK1.7中的实现,JDK1.7对1.6的非常多代码做了优化。比方上面这段扩容代码,在JDK1.6中上面的是直接除2,显然。移位运算要更高效。
10、在看看LinkedList中的add方法:
(1)、add(E e):
/**
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #addLast}.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
linkLast(e);
return true;
}
(2)、linkLast(E e) :
/**
* Links e as last element.
*/
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)、内部类:
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;
}
}
从这段add代码能够看出。LinkedList因为使用了链表。所以不须要进行扩容,直接把元素加到链表最后,把新元素的前驱指向之前的last元素。并把last元素指向新元素就能够了。
这也是一个O(1)的性能。
在任何位置插入元素
11、ArrayList中的实现例如以下:
(1)、 add(int index, E element)
public void add(int index, E element) {
rangeCheckForAdd(index);
// 推断容量
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
(2)、ensureCapacityInternal(int minCapacity)
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code,假设数组长度不够则进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
(3)、grow(int minCapacity)
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
这段代码,首先先检查数组容量,容量不够先扩容。然后把index之后的数组往后挪一个。最后在index位置放上新元素。因为数组是一块连续内存空间,所以在任何位置插入。都会导致这个其后数组后挪一位的情况。须要做一次数组复制操作,非常明显,假设有大量的随机插入,那么这个数组复制操作开销会非常大。并且插入的越靠前,数组复制开销越大。
12、LinkedList中的实现:
(1)、add(int index, E element)
/**
* 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) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
(2)、linkBefore(E e, Node<E> succ)
/**
* Inserts element e before non-null Node succ.
*/
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++;
}
(3)、 Node<E> node(int index)
/**
* Returns the (non-null) Node at the specified element index.
*/
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;
}
}
这段代码。取到原先index处节点的前驱。变成新节点的前驱,同一时候把原先index变成新节点的后驱,这样就完毕了新节点的插入。
这个就是链表的优势。不存在数据复制操作,性能和在最后插入是一样的。
小结:
从上面的源代码剖析能够看出这三种List实现的一些典型适用场景,假设常常对数组做随机插入操作,特别是插入的比較靠前,那么LinkedList的性能优势就很明显。而假设都仅仅是末尾插入,则ArrayList更占领优势。假设须要线程安全。则使用Vector或者创建线程安全的ArrayList。
在使用基于数组实现的ArrayList 和Vector 时我们要指定初始容量。由于我们在源代码中也看到了,在加入时首先要进行容量的推断,假设容量不够则要创建新数组。还要将原来数组中的数据拷贝到新数组中。这个过程会减低效率而且会浪费资源。
List接口实现类-ArrayList、Vector、LinkedList集合深入学习以及源代码解析的更多相关文章
- ArrayList Vector LinkedList(一)
ArrayList Vector LinkedList 区别与用法 ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素, ...
- HashMap,Hashset,ArrayList以及LinkedList集合的区别,以及各自的用法
基础内容 容器就是一种装其他各种对象的器皿.java.util包 容器:Set, List, Map ,数组.只有这四种容器. Collection(集合) 一个一个往里装,Map 一对一对往里装. ...
- paip.提升性能---list,arraylist,vector,linkedlist,map的选用..
paip.提升性能---list,arraylist,vector,linkedlist,map的选用.. arraylist,vector基本一样,但是,vector线程安全的. 作者Attilax ...
- 请说出ArrayList,Vector, LinkedList的存储性能和特性
请说出ArrayList,Vector, LinkedList的存储性能和特性 解答:ArrayList和Vector都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都 ...
- Java:类集框架中集合的学习
Java:类集框架中集合的学习 集合 Java:Set的学习 Set是类集框架中的集合类.集合是不按特定的方式排序,并且没有重复对象的一种类. Q:Set如何操作?Set中的不按特定方式排序是怎么排序 ...
- java中List接口的实现类 ArrayList,LinkedList,Vector 的区别 list实现类源码分析
java面试中经常被问到list常用的类以及内部实现机制,平时开发也经常用到list集合类,因此做一个源码级别的分析和比较之间的差异. 首先看一下List接口的的继承关系: list接口继承Colle ...
- java的List接口的实现类 ArrayList,LinkedList,Vector 的区别
Java的List接口有3个实现类,分别是ArrayList.LinkedList.Vector,他们用于存放多个元素,维护元素的次序,而且允许元素重复. 3个具体实现类的区别如下: 1. Array ...
- 集合框架-ArrayList,Vector,Linkedlist
// ClassCastException 报错,注意,千万要搞清楚类型 * Vector的特有功能: * 1:添加功能 * public void addElement(Object obj) -- ...
- java集合(ArrayList,Vector,LinkedList,HashSet,TreeSet的功能详解)
说起集合,我们会潜意识里想到另外一个与之相近的名词——数组,OK!两者确实有相似之处,但也正是这点才是我们应该注意的地方,下面简单列出了两者的区别(具体功能的不同学习这篇文章后就会明白了): 数组 长 ...
随机推荐
- Qt在各平台上的搭建qt-everywhere
Qt for windows7-64bit 在电脑上安装mingw(搜索mingw for windows),将C:\MinGW\bin添加进环境变量,打开命令行输入gcc --version和g++ ...
- Python中单引号、双引号和三引号的区别
ython单引号.双引号和三双引号的区别 python字符串通常有单引号('...').双引号("...").三引号("""..."&quo ...
- Windows SDK笔记(经典--一定要看)
Windows SDK笔记(一):Windows程序基本结构 一.概述 Windows程序具有相对固定的结构,对编写者而言,不需要书写整个过程,大部分过程由系统完成.程序中只要按一定的格式填写系统留给 ...
- [每日一题] 11gOCP 1z0-052 :2013-09-14 repeated parsing activity.................................A70
转载请注明出处:http://blog.csdn.net/guoyjoe/article/details/11699299 正确答案:D SQL语句的执行过程: 1.客户端输入sql语句update ...
- (3)选择元素——(4)css选择器(CSS selectors)
The jQuery library supports nearly all of the selectors included in CSS specifications 1 through 3, ...
- ThinkPHP - 关联模型 - 一对多
使用之前,先引入文件夹,否则相应的功能不能实现. 如果对thinkPHP不精通,使用或开发的时候,最好直接使用完成版本的ThinkPHP. 关系模型定义: <?php /** * 继承自 Rel ...
- D - 二叉树遍历(推荐)
二叉树遍历问题 Description Tree Recovery Little Valentine liked playing with binary trees very much. Her ...
- 键盘过滤第一个例子ctrl2cap(4.1~4.4)汇总,测试
键盘过滤第一个例子ctrl2cap(4.1~4.4)汇总,测试 完整源代码 /// /// @file ctrl2cap.c /// @author wowocock /// @date 2009-1 ...
- vmware时间不同步的问题
请以管理员身份运行(root)
- NET Core全新的开发体验
NET Core全新的开发体验 2016年6月27日,这是一个特殊的日子,微软全新的.NET开发平台.NET Core的RTM版本正式发布.我个人将.NET Core的核心特性归结为三点,它们的首字母 ...