一段有关List下集合性能的实验+JDK下源码

来源:互联网 发布:中日友好靠韩国 知乎 编辑:程序博客网 时间:2024/04/23 14:02
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;
  }
每次获取的时候,都要从刚开始的节点往下找,这有多出来了查找的开销,这只是个人的看法,我也不知道对不对,如果有错误的话,大家可以留言哦!


0 0