一、实现List的几个类:

ArrayList、LinkedList、CopyOnWriteArrayList、Vector

二、几个List底层的数据结构:

ArrayList - 数组列表

LinkedList - 双链表列表和队列(同时实现List和Queue接口)

Vector - 数组列表(加锁)

CopyOnWriteArrayList - 数组列表(读写分离)

三、List的几种基本操作比较

1、add操作比较

   /**
    * 比较add操作
    * @param minTimes 最小次数
    * @param maxTimes 最大次数
    * @param stepLen 步长
    */
   public static void compareAddMethod(int minTimes, int maxTimes, int stepLen) {
     Date begin = null;
     Date end = null;
     int times = minTimes;
     while(times < maxTimes) {

       //add: Vector
       Vector<Integer> vector = new Vector<Integer>();
       begin = new Date();
       for(int i=0; i<times; i++) {
         vector.add(i);
       }
       end = new Date();
       System.out.println("Vector add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //add: ArrayList
       ArrayList<Integer> arrayList = new ArrayList<Integer>();
       begin = new Date();
       for(int i=0; i<times; i++) {
         arrayList.add(i);
       }
       end = new Date();
       System.out.println("ArrayList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //add: LinkedList
       LinkedList<Integer> linkedList = new LinkedList<Integer>();
       begin = new Date();
       for(int i=0; i<times; i++) {
         linkedList.add(i);
       }
       end = new Date();
       System.out.println("LinkedList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //add: CopyOnWriteArrayList
       if(times<=100000) {
         CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
         begin = new Date();
         for(int i=0; i<times; i++) {
           copyOnWriteArrayList.add(i);
         }
         end = new Date();
         System.out.println("CopyOnWriteArrayList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
       }

       System.out.println("-------------------------------");
       times+=stepLen;
     }

运算结果:
minTimes = 0, maxTimes = 100000, stepLen = 30000
times Vector(ms) ArrayList(ms) LinkedList(ms) CopyOnWriteArrayList(ms)
0 0 0 0 0
30000 3 2 2 339
60000 3 4 1 992
90000 1 1 0 2257

结果分析:这里可以看出随着增加执行次数的增加CopyOnWriteArrayList所耗时增加较多,这是由于CopyOnWriteArrayList的读写策略造成。CopyOnWriteArrayList进行写操作,先对原底层数组进行复制,然后在复制数组进行写操作,最后复制数组对原数组引进行替换。这里的耗时消耗在复制数组上面,数组元素越多,所消耗的时间就越多。

minTimes = 0, maxTimes = 10000000, stepLen = 1000000
times Vector(ms) ArrayList(ms) LinkedList(ms)
0 0 0 0
1000000 37 20 29
2000000 613 396 603
3000000 80 56 174
4000000 169 27 112
5000000 195 44 91
6000000 235 43 80
7000000 261 56 103
8000000 287 60 226
9000000 362 64 209

结果分析:这里ArrayList的插入比LinkedList快的原因是每次添加元素都是从数组末尾添加,数组直接通过索引在数组末尾添加元素,和LinkedList链表相比省却了寻找节点的时间,若是换成随机添加删除节点的操作,ArrayList就会比LinkedList慢了。而Vector虽然和ArrayList的底层数据结构一样(可变长的数组),但是由于Vector是线程安全的,这导致执行效率会比较慢。

2、remove操作比较

   /**
    * 比较remove操作
    * @param minTimes 最小次数
    * @param maxTimes 最大次数
    * @param stepLen 步长
    */
   public static void compareRemoveMethod(int minTimes, int maxTimes, int stepLen) {
     Date begin = null;
     Date end = null;
     int times = minTimes;
     while(times < maxTimes) {

       //remove: Vector
       Vector<Integer> vector = new Vector<Integer>();
       for(int i=0; i<times; i++)
         vector.add(i);
       begin = new Date();
       for(int i=0; i<times; i++)
         vector.remove(0);
       end = new Date();
       System.out.println("Vector remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //remove: ArrayList
       ArrayList<Integer> arrayList = new ArrayList<Integer>();
       for(int i=0; i<times; i++)
         arrayList.add(i);
       begin = new Date();
       for(int i=0; i<times; i++)
         arrayList.remove(0);
       end = new Date();
       System.out.println("ArrayList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //remove: LinkedList
       LinkedList<Integer> linkedList = new LinkedList<Integer>();
       for(int i=0; i<times; i++)
         linkedList.add(i);
       begin = new Date();
       for(int i=0; i<times; i++)
         linkedList.remove(0);
       end = new Date();
       System.out.println("LinkedList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //remove: CopyOnWriteArrayList
       if(times<=100000) {
         CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
         for(int i=0; i<times; i++)
           copyOnWriteArrayList.add(i);
         begin = new Date();
         for(int i=0; i<times; i++)
           copyOnWriteArrayList.remove(0);
         end = new Date();
         System.out.println("CopyOnWriteArrayList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
       }

       System.out.println("-------------------------------");
       times+=stepLen;
     }
   }
运算结果:
minTimes = 0, maxTimes = 100000, stepLen = 30000
times Vector(ms) ArrayList(ms) LinkedList(ms) CopyOnWriteArrayList(ms)
0 0 0 0 0
30000 90 90 5 229
60000 356 351 1 921
90000 832 834 0 3199

结果分析:不出意外,CopyOnWriteArrayList的插入删除操作依旧是耗时最长的。值得注意的是,这里LinkedList的优势体现出来了,删除插入随机节点时链表操作比数组操作是更有效率的。

3、读取操作比较

   /**
    * 比较读取操作
    * @param minTimes 最小次数
    * @param maxTimes 最大次数
    * @param stepLen 步长
    */
   public static void compareReadMethod(int minTimes, int maxTimes, int stepLen) {
     Date begin = null;
     Date end = null;
     int times = minTimes;
     while(times < maxTimes) {

       //remove: Vector
       Vector<Integer> vector = new Vector<Integer>();
       for(int i=0; i<times; i++)
         vector.add(i);
       begin = new Date();
       for(int i=0; i<times; i++)
         vector.get(i);
       end = new Date();
       System.out.println("Vector get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //get: ArrayList
       ArrayList<Integer> arrayList = new ArrayList<Integer>();
       for(int i=0; i<times; i++)
         arrayList.add(i);
       begin = new Date();
       for(int i=0; i<times; i++)
         arrayList.get(i);
       end = new Date();
       System.out.println("ArrayList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       //get: LinkedList
       if(times<=100000) {
         LinkedList<Integer> linkedList = new LinkedList<Integer>();
         for(int i=0; i<times; i++)
           linkedList.add(i);
         begin = new Date();
         for(int i=0; i<times; i++)
           linkedList.get(i);
         end = new Date();
         System.out.println("LinkedList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
       }

       //get: CopyOnWriteArrayList
       CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
       for(int i=0; i<times; i++)
         copyOnWriteArrayList.add(i);
       begin = new Date();
       for(int i=0; i<times; i++)
         copyOnWriteArrayList.get(i);
       end = new Date();
       System.out.println("CopyOnWriteArrayList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");

       System.out.println("-------------------------------");
       times+=stepLen;
     }
   }
运算结果:

minTimes = 0, maxTimes = 100000, stepLen = 30000
times Vector(ms) ArrayList(ms) LinkedList(ms) CopyOnWriteArrayList(ms)
0 0 0 0 0
30000 2 2 334 0
60000 1 1 1313 0
90000 0 0 2945 0

结果分析:这里为什么LinkedList耗时比较长就不需要说明,这里Vector如果在同时频繁写操作的时候读写耗时便会比较长,而由于CopyOnWriteArrayList使用读写分离测的策略(写操作在复制数组中进行,读操作在原数组里面进行)平衡了线程安全和执行性能的矛盾。

四、小结

1、在List元素数量比较少的时候没必要纠结采用哪个List,因为规模小时根本体现不出什么差别,此时要注意是否选取线程安全的List,一般情况是不采取线程安全的List,而是在ArrayList和LinkedList之间选择。

2、Vector - 底层数据结构为可变长数组,数组长度按100%增长,线程安全,写效率低,读效率在多线程环境下也低。

3、ArrayList - 底层数据结构为可变长数组,数组长度按50%增长,线程不安全,随机插入删除操作效率低,随机读取修改元素效率高。

4、LinkedList - 底层数据结构为双向链表,线程不安全,随机插入删除操作效率高,随机读取修改元素效率低。

5、CopyOnWriteArrayList - 底层数据结构为可变长数组,线程安全,写效率低,读效率在多线程环境下也高,但是由于读写分离,读数据可能出现过时的情况(不可重复读)

6、这里CopyOnWriteArrayList读写分离的思想值得我学习。

[知识整理]Java集合(一) - List的更多相关文章

  1. [知识整理]Java集合

    Mark Java集合图

  2. [知识整理]Java集合(二) - Set

    一.实现Set的几个类 HashSet.LinkedHashSet.TreeSet.ConcurrentSkipListSet.CopyOnWriterArraySet 二.对应底层的数据结构 Has ...

  3. 《Java基础知识》Java集合(Collection)

    作为一个Developer,Java集合类是我们在工作中运用最多的.最频繁的类.相比于数组(Array)来说,集合类的长度可变,更加适合于现代开发需求: Java集合就像一个容器,可以存储任何类型的数 ...

  4. 《Java基础知识》Java集合(Map)

    Java集合主要由2大体系构成,分别是Collection体系和Map体系,其中Collection和Map分别是2大体系中的顶层接口. 今天主要讲:Map主要有二个子接口,分别为HashMap.Tr ...

  5. Java基础知识(JAVA集合框架之List与Set)

    List和Set概述数组必须存放同一种元素.StringBuffer必须转换成字符串才能使用,如果想拿出单独的一个元素几乎不可能.数据有很多使用对象存,对象有很多,使用集合存. 集合容器因为内部的数据 ...

  6. 面试知识整理-Java基础

    三大特征:封装,继承,多态 多态:简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情. 抽象:抽象是将一类对象的共同特征总结出来构造类的过程 包装,可以讲基本类型当做对象来使用,抽象只关心对 ...

  7. 学习:java集合

    java是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台(即JavaEE, JavaME, Jav ...

  8. Java集合--HashMap分析

    HashMap在Java开发中有着非常重要的角色地位,每一个Java程序员都应该了解HashMap. 本文主要从源码角度来解析HashMap的设计思路,并且详细地阐述HashMap中的几个概念,并深入 ...

  9. Java集合框架相关知识整理

    1.常见的集合有哪些? Collection接口和Map接口是所有集合框架的父接口    Collection接口的子接口包括:Set接口和List接口    Map接口的实现类主要有:HashMap ...

随机推荐

  1. ORA-12519, ORA-00020异常产生原因及解决方案

    近期在做项目的过程中,使用oracle时碰到了如下两个异常: ORA-12519, TNS:no appropriate service handler found: ORA-00020:maximu ...

  2. TestNG @Factory与 @DataProvider 结合使用进行参数化测试

    简介 TestNG是一个设计用来简化广泛的测试需求的测试框架,从单元测试到集成测试,这个是TestNG设计的出发点,不仅仅是单元测试,而且可以用于集成测试.设计目标的不同,对比junit的只适合用于单 ...

  3. 一次完整的HTTP请求流程

    HTTP通信机制是在一次完整的HTTP通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: 1. 建立TCP连接: 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接, ...

  4. 在Excel中将数字转换为大写

    123.09 = 壹佰贰拾叁元零玖分 =SUBSTITUTE(SUBSTITUTE(IF(G10<0,"負","")&TEXT(TRUNC(ABS ...

  5. 【转载】快速收索并更新sid 方法

    利用Google的搜索功能,可以获得不少SAS各个版本的SID号,试过之后你会异常惊喜.1.打开谷歌: http://google.com.hk2.输入或复制这个段文字:"SID_heade ...

  6. 规则引擎集成接口(四)SQL执行语句

    SQL执行语句 右键点击数据库连接文件“hr”—“添加SQL执行语句”,如下图: 弹出窗体,如下图: 将显示名称改为“部门名称”,返回至类型设置为“string”,在编写sql语句,如下图: 点击确定 ...

  7. matlab函数_连通区域

    1. matlab函数bwareaopen──删除小面积对象格式:BW2 = bwareaopen(BW,P,conn)作用:删除二值图像BW中面积小于P的对象,默认情况下使用8邻域.算法:(1)De ...

  8. AChartEngine 图表绘制

    AChartEngine Android 平台的图表开发库, 能绘制 折线图, 饼图, 气泡图, 柱状图, 散点图, 面积图等统计图表. 这些我记录一下,柱状图.折线图和饼状图的小例子.有兴趣的朋友, ...

  9. 输入m乘法表

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 关键字extern

    extern 可以置于  变量  或  函数  前,  以表明变量 或 函数 的定义在别的文件中,  下面代码用到的这些变量  或 函数是外来的,  不是本文件定义的, 提示链接器遇到此变量和函数时在 ...