[知识整理]Java集合(一) - List

一、实现List的几个类:

ArrayList、LinkedList、CopyOnWriteArrayList、Vector

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

ArrayList - 数组列表

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

Vector - 数组列表(加锁)

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

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

1、add操作比较

 1   /**
 2    * 比较add操作
 3    * @param minTimes 最小次数
 4    * @param maxTimes 最大次数
 5    * @param stepLen 步长
 6    */
 7   public static void compareAddMethod(int minTimes, int maxTimes, int stepLen) {
 8     Date begin = null;
 9     Date end = null;
10     int times = minTimes;
11     while(times < maxTimes) {
12
13       //add: Vector
14       Vector<Integer> vector = new Vector<Integer>();
15       begin = new Date();
16       for(int i=0; i<times; i++) {
17         vector.add(i);
18       }
19       end = new Date();
20       System.out.println("Vector add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
21
22       //add: ArrayList
23       ArrayList<Integer> arrayList = new ArrayList<Integer>();
24       begin = new Date();
25       for(int i=0; i<times; i++) {
26         arrayList.add(i);
27       }
28       end = new Date();
29       System.out.println("ArrayList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
30
31       //add: LinkedList
32       LinkedList<Integer> linkedList = new LinkedList<Integer>();
33       begin = new Date();
34       for(int i=0; i<times; i++) {
35         linkedList.add(i);
36       }
37       end = new Date();
38       System.out.println("LinkedList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
39
40       //add: CopyOnWriteArrayList
41       if(times<=100000) {
42         CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
43         begin = new Date();
44         for(int i=0; i<times; i++) {
45           copyOnWriteArrayList.add(i);
46         }
47         end = new Date();
48         System.out.println("CopyOnWriteArrayList add "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
49       }
50
51       System.out.println("-------------------------------");
52       times+=stepLen;
53     }
运算结果:
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操作比较

 1   /**
 2    * 比较remove操作
 3    * @param minTimes 最小次数
 4    * @param maxTimes 最大次数
 5    * @param stepLen 步长
 6    */
 7   public static void compareRemoveMethod(int minTimes, int maxTimes, int stepLen) {
 8     Date begin = null;
 9     Date end = null;
10     int times = minTimes;
11     while(times < maxTimes) {
12
13       //remove: Vector
14       Vector<Integer> vector = new Vector<Integer>();
15       for(int i=0; i<times; i++)
16         vector.add(i);
17       begin = new Date();
18       for(int i=0; i<times; i++)
19         vector.remove(0);
20       end = new Date();
21       System.out.println("Vector remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
22
23       //remove: ArrayList
24       ArrayList<Integer> arrayList = new ArrayList<Integer>();
25       for(int i=0; i<times; i++)
26         arrayList.add(i);
27       begin = new Date();
28       for(int i=0; i<times; i++)
29         arrayList.remove(0);
30       end = new Date();
31       System.out.println("ArrayList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
32
33       //remove: LinkedList
34       LinkedList<Integer> linkedList = new LinkedList<Integer>();
35       for(int i=0; i<times; i++)
36         linkedList.add(i);
37       begin = new Date();
38       for(int i=0; i<times; i++)
39         linkedList.remove(0);
40       end = new Date();
41       System.out.println("LinkedList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
42
43       //remove: CopyOnWriteArrayList
44       if(times<=100000) {
45         CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
46         for(int i=0; i<times; i++)
47           copyOnWriteArrayList.add(i);
48         begin = new Date();
49         for(int i=0; i<times; i++)
50           copyOnWriteArrayList.remove(0);
51         end = new Date();
52         System.out.println("CopyOnWriteArrayList remove "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
53       }
54
55       System.out.println("-------------------------------");
56       times+=stepLen;
57     }
58   }
运算结果:
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、读取操作比较

 1   /**
 2    * 比较读取操作
 3    * @param minTimes 最小次数
 4    * @param maxTimes 最大次数
 5    * @param stepLen 步长
 6    */
 7   public static void compareReadMethod(int minTimes, int maxTimes, int stepLen) {
 8     Date begin = null;
 9     Date end = null;
10     int times = minTimes;
11     while(times < maxTimes) {
12
13       //remove: Vector
14       Vector<Integer> vector = new Vector<Integer>();
15       for(int i=0; i<times; i++)
16         vector.add(i);
17       begin = new Date();
18       for(int i=0; i<times; i++)
19         vector.get(i);
20       end = new Date();
21       System.out.println("Vector get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
22
23       //get: ArrayList
24       ArrayList<Integer> arrayList = new ArrayList<Integer>();
25       for(int i=0; i<times; i++)
26         arrayList.add(i);
27       begin = new Date();
28       for(int i=0; i<times; i++)
29         arrayList.get(i);
30       end = new Date();
31       System.out.println("ArrayList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
32
33       //get: LinkedList
34       if(times<=100000) {
35         LinkedList<Integer> linkedList = new LinkedList<Integer>();
36         for(int i=0; i<times; i++)
37           linkedList.add(i);
38         begin = new Date();
39         for(int i=0; i<times; i++)
40           linkedList.get(i);
41         end = new Date();
42         System.out.println("LinkedList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
43       }
44
45       //get: CopyOnWriteArrayList
46       CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<Integer>();
47       for(int i=0; i<times; i++)
48         copyOnWriteArrayList.add(i);
49       begin = new Date();
50       for(int i=0; i<times; i++)
51         copyOnWriteArrayList.get(i);
52       end = new Date();
53       System.out.println("CopyOnWriteArrayList get "+times+" times, cost: "+(end.getTime()-begin.getTime())+"ms");
54
55       System.out.println("-------------------------------");
56       times+=stepLen;
57     }
58   }
运算结果:

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读写分离的思想值得我学习。

时间: 2024-08-08 16:34:09

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

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

一.实现Set的几个类 HashSet.LinkedHashSet.TreeSet.ConcurrentSkipListSet.CopyOnWriterArraySet 二.对应底层的数据结构 HashSet - 哈希表 LinkedHashSet - 哈希表和链表 TreeSet - 红黑树 ConcurrentSkipListSet - 跳表 CopyOnWriteArraySet - 数组列表 三.应用场景 这里先从元素是否有序,按照什么顺序来应用进行Set的选择,最后再从线程安全的角度说

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

作为一个Developer,Java集合类是我们在工作中运用最多的.最频繁的类.相比于数组(Array)来说,集合类的长度可变,更加适合于现代开发需求: Java集合就像一个容器,可以存储任何类型的数据,也可以结合泛型来存储具体的类型对象.在程序运行时,Java集合可以动态的进行扩展,随着元素的增加而扩大.在Java中,集合类通常存在于java.util包中. Java集合主要由2大体系构成,分别是Collection体系和Map体系,其中Collection和Map分别是2大体系中的顶层接口.

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

Java集合主要由2大体系构成,分别是Collection体系和Map体系,其中Collection和Map分别是2大体系中的顶层接口. 今天主要讲:Map主要有二个子接口,分别为HashMap.TreeMap. 继承关系图: Map的整体特点: 1. 键值对存放<key , value> 2. 遍历需要使用迭代器:Iterator 常用Map HashMap import java.util.HashMap; import java.util.Map; public class var {

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

List和Set概述数组必须存放同一种元素.StringBuffer必须转换成字符串才能使用,如果想拿出单独的一个元素几乎不可能.数据有很多使用对象存,对象有很多,使用集合存. 集合容器因为内部的数据结构不同有多种具体容器,不断的向上抽取就形成了集合框架.框架的顶层就是Collection接口. List:列表.元素可以重复,有序(存入和取出有特定的顺序).List下有三个类比较常用:Vector.ArrayList.LinkedList. Vector类.Vector类自JDK1.0就出现了,

Java知识整理--Java的List用法

list中可以添加任何对象,举例: class Node { ..... } 上面定义了一个Node类,下面使用List Node n1 = new Node(); Node n2 = new Node(); List list=new ArrayList(); list.add(n1); list.add(n2); //这里是将对象加入到list中 for(int i=0;i<list.size();i++){//利用循环,将Node对象全部一一取出 Node n = (Node)list.g

Java基础知识整理(一)

概述 公司业务需要,产品既要有.NET又需要Java,没得选择,只能业余时间学习Java,整体觉得Java也.NET还是很相似的,只是语法有差别,差别也不是很大,这就将学习Java的基础知识整理下,以便于自己的学习.作为个.NET程序猿也可以学习Java ,毕竟技多不压身,学习多也要精通. 开发工具 eclipse ,开发java类似.NET 需要装JDK类似.NET Framework. Java开发工具eclipse设置 1.设置字体:window设置: 2.设置快捷键:window--ke

Java集合框架的知识总结

说明:面试准备,写的挺不错的. 转载地址: http://www.cnblogs.com/zhxxcq/archive/2012/03/11/2389611.html 1.综述 所有集合类都位于java.util包下.集合中只能保存对象(保存对象的引用变量).(数组既可以保存基本类型的数据也可以保存对象). 当我们把一个对象放入集合中后,系统会把所有集合元素都当成Object类的实例进行处理.从JDK1.5以后,这种状态得到了改进:可以使用泛型来限制集合里元素的类型,并让集合记住所有集合元素的类

JAVA基础知识整理

一.首先先明白get与post的基本定义和区别: 这是两种在客户端和服务器端进行请求-响应的方法. 1get:从指定的资源请求数据. 2post:向指定的资源提交要处理的数据. get基本上用于从服务器取回数据,注意:get方法可能返回缓存数据. post可以从服务器上获取数据,不过,post方法不会缓存数据,并且常用语连同请求一起发送数据. 二. Jquery $.get()方法. $.get()方法通过Http Get发起请求,从服务器上请求数据. 语法:&.get(URL,callback

java复习整理之集合

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.ios培训..Net培训</a>.期待与您交流!------ java复习整理之集合: Collection:集合中的最顶层接口,提供了一些操作集合的共性方法添加:boolean add(E e)boolean addAll(Collection<? extends E> c)删除:void