1.List下包含了ArrayList,Stack,Vector,LinkedList四个实现的常用的集合类,其内部的结构大致分为
对于有关他们之间的增删查的性能的分析,我从其他地方看到了一行代码,很好,就复制下来给大家
package com.shaoxu.test.collection;
import java.util.*;
import java.lang.Class;
/*
* @desc 对比ArrayList和LinkedList的插入、随机读取效率、删除的效率
*
* @author skywang
*/
public class ListCompareTest {
private static final int COUNT = 100000;
private static LinkedList linkedList = new LinkedList();
private static ArrayList arrayList = new ArrayList();
private static Vector vector = new Vector();
private static Stack stack = new Stack();
public static Integer obj ;
public static void main(String[] args) {
// 换行符
System.out.println();
// 插入
insertByPosition(stack) ;
insertByPosition(vector) ;
insertByPosition(linkedList) ;
insertByPosition(arrayList) ;
// 换行符
System.out.println();
// 随机读取
readByPosition(stack);
readByPosition(vector);
readByPosition(linkedList);
readByPosition(arrayList);
// 换行符
System.out.println();
// 删除
deleteByPosition(stack);
deleteByPosition(vector);
deleteByPosition(linkedList);
deleteByPosition(arrayList);
}
// 获取list的名称
private static String getListName(List list) {
if (list instanceof LinkedList) {
return "LinkedList";
} else if (list instanceof ArrayList) {
return "ArrayList";
} else if (list instanceof Stack) {
return "Stack";
} else if (list instanceof Vector) {
return "Vector";
} else {
return "List";
}
}
// 向list的指定位置插入COUNT个元素,并统计时间
private static void insertByPosition(List list) {
long startTime = System.currentTimeMillis();
// 向list的位置0插入COUNT个数
for (int i=0; i<COUNT; i++){
obj=new Integer(i) ;
list.add(0, obj);
}
long endTime = System.currentTimeMillis();
long interval = endTime - startTime;
System.out.println(getListName(list) + " : insert "+COUNT+" elements into the 1st position use time:" + interval+" ms");
}
// 从list的指定位置删除COUNT个元素,并统计时间
private static void deleteByPosition(List list) {
long startTime = System.currentTimeMillis();
// 删除list第一个位置元素
for (int i=0; i<COUNT; i++)
list.remove(0);
long endTime = System.currentTimeMillis();
long interval = endTime - startTime;
System.out.println(getListName(list) + " : delete "+COUNT+" elements from the 1st position use time:" + interval+" ms");
}
// 根据position,不断从list中读取元素,并统计时间
private static void readByPosition(List list) {
long startTime = System.currentTimeMillis();
// 读取list元素
for (int i=0; i<COUNT; i++)
list.get(i);
long endTime = System.currentTimeMillis();
long interval = endTime - startTime;
System.out.println(getListName(list) + " : read "+COUNT+" elements by position use time:" + interval+" ms");
}
}
直接运行,你会发现他们之间的性能问题就浮现出来了
Stack : insert 100000 elements into the 1st position use time:1405 ms
Vector : insert 100000 elements into the 1st position use time:1244 ms
LinkedList : insert 100000 elements into the 1st position use time:11 ms
ArrayList : insert 100000 elements into the 1st position use time:1232 ms
Stack : read 100000 elements by position use time:2 ms
Vector : read 100000 elements by position use time:3 ms
LinkedList : read 100000 elements by position use time:10901 ms
ArrayList : read 100000 elements by position use time:1 ms
Stack : delete 100000 elements from the 1st position use time:862 ms
Vector : delete 100000 elements from the 1st position use time:862 ms
LinkedList : delete 100000 elements from the 1st position use time:2 ms
ArrayList : delete 100000 elements from the 1st position use time:875 ms
通过上面的内容,就可以看出来LinkedList在制定位置插入和删除的时候较性能高一些,而ArrayList在随机访问的时候性能较为高一些,其实也是,我有看了JDK中的代码,特此比较一下
对于ArrayList的add的时候,调用最终的 方法为
...
public void add(int paramInt, E paramE)
{
rangeCheckForAdd(paramInt);
ensureCapacityInternal(this.size + 1);
System.arraycopy(this.elementData, paramInt, this.elementData, paramInt + 1, this.size - paramInt);
this.elementData[paramInt] = paramE;
this.size += 1;
}
由上可知,add的时候ArrayList只是增加一个指定位置的值的数组,而且还要arrayCopy出一个新的数组对象,花销比较大,然后你再看LinkedList的add源码
...
public void add(int paramInt, E paramE)
{
checkPositionIndex(paramInt);
if (paramInt == this.size)
linkLast(paramE);
else
linkBefore(paramE, node(paramInt));
}
Node<E> node(int paramInt)
{
if (paramInt < this.size >> 1)
{
localNode = this.first;
for (i = 0; i < paramInt; ++i)
localNode = localNode.next;
return localNode;
}
Node localNode = this.last;
for (int i = this.size - 1; i > paramInt; --i)
localNode = localNode.prev;
return localNode;
}
你会发现,他是一个链表,每次添加的时候少了重新copy为新数组的开销,添加起来也就更快了
除LinkedList之外,其余三个都是数组的形式来存值的,因此在插入的时候没有什么较大的差距,这里不一一查看了,如果想了解他们之间的细微差别,可以看他们的jdk的源码
添加和删除其实一样,就是数组和链表的区别
为什么LinkedList的随机读取这么费事呢,这就体现出来数组的读取的优势了,
请看ArrayList的get方法:
...
public E get(int paramInt)
{
rangeCheck(paramInt);
return elementData(paramInt);
}
E elementData(int paramInt)
{
return this.elementData[paramInt];
}
直接返回已经初始化好的数组对应的索引的值即可,而对于LinkedList而言,请看代码
public E get(int paramInt)
{
checkElementIndex(paramInt);
return node(paramInt).item;
}
Node<E> node(int paramInt)
{
if (paramInt < this.size >> 1)
{
localNode = this.first;
for (i = 0; i < paramInt; ++i)
localNode = localNode.next;
return localNode;
}
Node localNode = this.last;
for (int i = this.size - 1; i > paramInt; --i)
localNode = localNode.prev;
return localNode;
}
每次获取的时候,都要从刚开始的节点往下找,这有多出来了查找的开销,这只是个人的看法,我也不知道对不对,如果有错误的话,大家可以留言哦!