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 好 好 好 差 极优
下面举例来说明它们在性能上的区别。
执行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在删除,插入,迭代取值上有较高的性能。
概要
我们在 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在删除,插入,迭代取值上有较高的性能。
相关文章推荐
- Java Collections Framework - Java集合框架之List篇 ArrayList与LinkedList等的性能比较
- Java Collections Framework - Java集合框架之List篇 ArrayList与LinkedList等的性能比较
- Java中arraylist和linkedlist源码分析与性能比较
- 比较Java数组,ArrayList,LinkedList,Vector 性能比较
- java性能优化-Arraylist与Linkedlist整改查性能比较
- Java性能优化-Arraylist与Linkedlist整改查性能比较的简介与内容
- Java 集合系列08之 List总结(LinkedList, ArrayList等使用场景和性能分析)
- [转载] Java ArrayList、LinkedList、Vector比较
- ArrayList与LinkedList性能比较
- ArrayList和LinkedList性能比较
- Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比较
- Java 集合系列08之 List总结(LinkedList, ArrayList等使用场景和性能分析)
- Java容器(二)——「ArrayList、LinkedList性能测试与分析」
- Java 集合系列之 List总结(LinkedList, ArrayList等使用场景和性能分析)
- java-集合(4)-用LinkedList来实现栈/队列-ArrayList和LinkedList比较
- Java学习之为什么说LinkedList的插入和删除性能比ArrayList好,而ArrayList的查询更好?
- Java 集合系列08之 List总结(LinkedList, ArrayList等使用场景和性能分析)
- Java使用Arrays、ArrayList、LinkedList、Vector实现插入查询性能分析
- Java中LinkedList与ArrayList遍历速度比较
- java的list几种实现方式的效率(ArrayList、LinkedList、Vector、Stack),以及 java时间戳的三种获取方式比较