您的位置:首页 > 编程语言 > Java开发

Java Collections Framework - Java集合框架之List篇 ArrayList与LinkedList等的性能比较

2009-09-23 16:25 507 查看
Java Collections Framework的List集合类主要有ArrayList,LinkedList,Vector,Stack等。本文主要对它们作一个比较,说明它们的异同点以及性能上的区别等。

概要
我们在 Java Collections Framework - Java集合框架List,Map,Set等全面介绍之概要篇 一文中对Java集合框架(Java Collections Framework)做了一个比较全面的介绍。

该文粗略地介绍了List集合的概念定义等。

List集合
List继承自Collection接口。List是一种有序集合,List中的元素可以根据索引(顺序号:元素在集合中处于的位置信息)进行取得/删除/插入操作。
跟Set集合不同的是,List允许有重复元素。对于满足e1.equals(e2)条件的e1与e2对象元素,可以同时存在于List集合中。当然,也有List的实现类不允许重复元素的存在。
同时,List还提供一个listIterator()方法,返回一个ListIterator接口对象,和Iterator接口相比,ListIterator添加元素的添加,删除,和设定等方法,还能向前或向后遍历。

List跟Collection的关系:
java.util.Collection [I]
+--java.util.List [I]
+--java.util.ArrayList [C]
+--java.util.LinkedList [C]
+--java.util.Vector [C]
+--java.util.Stack [C]

List接口的实现类主要有ArrayList,LinkedList,Vector,Stack等。

本文主要对上面提到的几个类作一个比较,说明它们的异同点以及性能上的区别等。

ArrayList,LinkedList,Vector,Stack的相同点
ArrayList,LinkedList,Vector,Stack等类都实现了List接口,都属于List集合。
List接口里定义的基本方法是一样的。
public interface List
extends Collection
{
//... other Collection methods

//根据索引取得元素
public abstract Object get(int i);
//在指定位置(索引)处插入新的元素
public abstract Object set(int i, Object obj);
//在List的尾部插入新的元素
public abstract void add(int i, Object obj);
//删除指定位置(索引)处的元素
public abstract Object remove(int i);
//取得指定对象的最开始的索引位置
public abstract int indexOf(Object obj);
//取得指定对象的最后的索引位置
public abstract int lastIndexOf(Object obj);
//List提供的新的遍历方法
public abstract ListIterator listIterator();
//从指定位置i处开始迭代。最初next()方法返回的将是位置i处的元素。
public abstract ListIterator listIterator(int i);
//取得从位置i到j的所有元素(包含i但不包含j位置的元素),返回一个新的集合对象。
public abstract List subList(int i, int j);
}

ArrayList,LinkedList,Vector,Stack的相异之处:
数据构造上的差异:
ArrayList,Vector,Stack 都是使用动态数组来保存集合中的对象元素,亦即ArrayList,Vector,Stack具有基本相似的数据结构。ArrayList,Vector 除了以下所说的线程同步上的差异之外,它们的功能基本一样;Vector从Stack继承,除了拥有Stack具有的功能之外,还实现了栈的功能。
而LinkedList则使用链表的形式来保存集合中的对象元素。

线程处理上的差异:
ArrayList,LinkedList没有使用synchronized对线程同步作任何处理,也就是说它们在同一时刻可以由多个线程访问,不是线程安全的;
Vector,Stack则使用synchronized对主要方法作了同步控制,它们在同一时刻只能由一个线程访问。

ArrayList,LinkedList,Vector,Stack的性能比较:
因为数据构造上的差异,它们在处理元素的添加,删除,插入,索引取值,遍历取值方面的效率上也各不相同。
ArrayList,Vector,Stack都是采用动态数组,它们的处理效率基本一样。
LinkedList采用链表构造,所以它跟ArrayList,Vector,Stack在添加,删除,插入,取值操作上就很大差异。
在具体的应用中,为了性能,功能上的考虑,我们可以根据具体的需求采用不同的List。

ArrayList,Vector,Stack

元素添加操作
ArrayList,Vector,Stack添加元素时的基本步骤是:
- 确保动态数组的空间大小。若空间不够时,则为集合元素重新分配空间,新分配的空间是原有空间大小的1.5倍左右,并把原来的集合元素拷贝到新分配的空间上。所以如果对象元素很多,有可能分配的空间大小要远远多出实际的元素,所以为了内存利用效率考虑,使用ArrayList等时,如果事先知道元素的多少,最好初始化时为其分配最大空间。
- 设置新元素到size+1位置。
大量添加时的性能:因为重新分配空间的次数不会太多,性能评价:好
元素删除操作
- 将删除位置i以后的元素全部往前移一个位置
- 设置size处元素为null
大量删除时的性能:因为每个元素的删除都会进行移位拷贝,性能评价:差
元素插入操作
- 同 元素添加操作
- 将插入位置i及以后的所有元素往后移一个位置
- 设置新元素至插入位置i
大量插入时的性能:因为每个元素的插入都会进行移位拷贝,性能评价:差
索引取值/遍历取值
因为是动态数组结构,所以索引取值(根据数组的下标)的速度非常快。
它们的遍历取值(Iterator.next())的内部实现是根据当前元素的位置取得下一个元素,所以跟索引取值一样,都是简单地引用数组的下标,所以速度也非常快。
性能评价:极优

LinkedList

元素添加操作
元素删除操作
元素插入操作
LinkedList的元素添加,删除,插入的操作步骤一样:
- 定位需要操作的元素
- 执行添加,删除,插入操作
虽然在元素的定位操作上需要花些时间,但LinkedList在处理时对元素的定位作了优化,性能评价:好
索引取值
因为LinkedList的链表结构,所以对元素的索引取值是一个遍历的过程,性能评价:极差
遍历取值
LinkedList在遍历的时候保存了当前元素,因为它的链表结构,可以快速的定位下一个元素。性能评价:极优

性能总结:
- add()操作 delete()操作 insert操作 index取值操作 iterator取值操作
ArrayList/Vector/Stack 好 差 差 极优 极优
LinkedList 好 好 好 差 极优

下面举例来说明它们在性能上的区别。

package com.test.collection;

import java.util.Iterator;
import java.util.List;

public class TestList {

/**
* List集合性能测试类
* Usage: java com.test.collection.TestList ListClassName MAX_TIMES
* 例:java com.test.collection.TestList LinkedList 100000
*/
public static void main(String[] args) {

if (args != null && args.length == 2) {
testList(args[0], Integer.parseInt(args[1]));
} else {
testList("LinkedList", 20000);

testList("ArrayList", 20000);
}
}

private static void testList(String listName, int maxElements) {
List list = null;
try {
list = (List) Class.forName("java.util." + listName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}

addElement2List(list, maxElements);
deleteElement2List(list);
insertElement2List(list, maxElements);
getListElementByIndex(list);
getListElementByIterator(list);
}

//add elements to List
private static void addElement2List(List list, int maxElements) {
long start = System.currentTimeMillis();

for (int i = 1; i < maxElements; i++) {
list.add(new Integer(i));
}

long end = System.currentTimeMillis();

printTime(list, end-start, " [add] ");
}

//remove elements from List
private static void deleteElement2List(List list) {
long start = System.currentTimeMillis();

while (!list.isEmpty()) {
list.remove(0);
}

long end = System.currentTimeMillis();

printTime(list, end-start, " [delete] ");
}

//insert elements to List
private static void insertElement2List(List list, int maxElements) {
long start = System.currentTimeMillis();

for (int i = 1; i < maxElements; i++) {
list.add(0, new Integer(i));
}

long end = System.currentTimeMillis();

printTime(list, end-start, " [insert] ");
}

private static void getListElementByIndex(List list) {
long start = System.currentTimeMillis();

for (int i = 1; i < list.size(); i++) {
Integer ele = (Integer)list.get(i);
}

long end = System.currentTimeMillis();

printTime(list, end-start, " [index] ");
}

private static void getListElementByIterator(List list) {
long start = System.currentTimeMillis();

Iterator ite = list.iterator();
while (ite.hasNext()) {
Integer ele = (Integer)ite.next();
}

long end = System.currentTimeMillis();

printTime(list, end-start, " [iterator] ");
}

private static void printTime(List list, long time, String operation) {
String out = list.getClass().getSimpleName();

out += " " + operation + ": " + time;

System.out.println(out);
}

}


执行Client,输出结果:

C:/test/list>java com.test.collection.TestList ArrayList 100000
ArrayList [add] : 79
ArrayList [delete] : 8703
ArrayList [insert] : 9281
ArrayList [index] : 0
ArrayList [iterator] : 16

C:/test/list>java com.test.collection.TestList LinkedList 100000
LinkedList [add] : 125
LinkedList [delete] : 16
LinkedList [insert] : 78
LinkedList [index] : 80328
LinkedList [iterator] : 0

C:/test/list>java com.test.collection.TestList Vector 100000
Vector [add] : 63
Vector [delete] : 8546
Vector [insert] : 9422
Vector [index] : 16
Vector [iterator] : 0

C:/test/list>java com.test.collection.TestList Stack 100000
Stack [add] : 47
Stack [delete] : 8593
Stack [insert] : 9610
Stack [index] : 0
Stack [iterator] : 16

总结:
本文主要比较了ArrayList,Vector,Stack与LinkedList的操作性能。
ArrayList,Vector与Stack在索引取值,迭代取值上有较高的性能。
LinkedList在删除,插入,迭代取值上有较高的性能。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐