java集合系列01--ArrayList
来源:互联网 发布:手机上怎样改淘宝评价 编辑:程序博客网 时间:2024/05/22 04:52
以下几篇文章都是对java集合的一个介绍,这些文章并非都是我的原创,主要是集合了各种途径获取的一个总结。对于集合,我们主要从以下四点关注:
1.是否允许为空;
2.是否允许重复数据;
3.是否有序,有序是指读取顺序与存放顺序是否一致;
4.是否线程安全。
ArrayList
(1)ArrayList 是一个数组队列,相当于动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。
(2)ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
(3)ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较List的“快速随机访问”和“通过Iterator迭代器访问”的效率。
(4)ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
(5)ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。
(6)和Vector不同,ArrayList中的操作不是线程安全的!所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。
ArrayList是一个以数组形式实现的集合,首先我们来看一下ArrayList的基本元素。
ArrayList与Collection的关系如图:
ArrayList包含了两个重要的对象:elementData和Size。
(1)elementData是“Object[]类型的数组”,它保存了添加到ArrayList中的的元素。实际上,elementData是一个动态数组,我们可以通过构造函数ArrayList(int initialCapacity)来执行它的初始化容量;如果通过不含参数的构造函数ArrayList()来创建,则它的默认容量是10。
(2)size是动态数组的实际大小。
添加元素
public class Test { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("00"); list.add("11"); }}
我们来看一下添加操作的底层源码实现:
public boolean add(E e) { //这个方法是为了实现扩容的作用 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
底层在调用add方法的时候只是给elementData的某个位置添加了一个数据而已,下图为例
为了方便理解才这样画的,elementData中存储的应该是堆内存中元素的引用,而不是实际的元素,这样画会让人误以为elementData中存放了实际元素,在这里提醒一下。
*扩容*
数组扩容的时候我们会先把数组乘以3,再除2后加1.为什么这样呢?
1、如果一次性扩容太大,必然会造成空间的浪费。
2、如果一次扩容不够,那么下一次扩容操作会很快发生,这回降低程序的运行效率,要知道扩容还是比较耗费性能的;
所以扩容多少,是jdk开发人员在时间和空间上的一个权衡。最后调用的是Arrays的copyOf方法,将原数组里的内容全部复制到新的数组里面。
删除元素
ArrayList支持两种删除方式:1.按照下标删除;2.按照元素删除,这会删除与指定元素相同的第一个元素。
//jdk源码public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work return oldValue; }
两种删除方式都是调用这段代码。都是做了两件事:
1、将指定元素后面位置的所有元素,利用System.arraycopy方法整体向前移动一位。
2、最后一个位置的元素指定外围null,这样gc就会去回收它。
插入元素
插入元素用的也是add方法,其方法与删除操作类似。
ArrayList的遍历方式
(1)通过迭代器遍历
//迭代器遍历 String value = null; Iterator it = list.iterator(); while(it.hasNext()) { value = (String) it.next(); System.out.println(value); } System.out.println("--------分割线-----------"); //随机访问,通过索引遍历 String value2 = null; for(int i = 0; i < list.size(); i++) { value = list.get(i); } String value3 = null; //for循环遍历 for(String str : list) { value3 = str; }
那么我们来比较一下它们的运行效率如何:
运行结果:
iteratorThroughRandomAccess:3 ms
iteratorThroughIterator:8 ms
iteratorThroughFor2:5 ms
由此可见,遍历ArrayList时,使用随机访问(即,通过索引序号访问)效率最高,而使用迭代器的效率最低!
ArrayList的优缺点
优点:
1、ArrayList底层是以数组实现,是一种随机访问模式,再加上实现了RandomAccess接口,因此查找也就是get非常快。
2、ArrayList顺序添加非常方便。
缺点:
无论是删除或插入元素(除非是最后一个元素)都涉及到一次元素复制,如果比较多则是一个耗费性能的过程。
因此ArrayList比较适合顺序添加、随机访问的场景。
ArrayList和Vector的区别
ArrayList是线程非安全的,这很明显,因为ArrayList中所有方法都不是同步的,在并发的情况下一定会出现线程安全问题。那么解决方法有两种:
1、使用Collections.synchronizedList方法把ArrayList变成一个线程安全的List。
List<String> synchronizedList = Collections.synchronizedList(list); synchronizedList.add("44");
2、另一个方法就是使用vector,它是ArrayList线程安全版本,大部分实现完全一样,区别在于:
1、vector是线程安全的,ArrayList是非线程安全;
2、vector可以指定增长因子,如果该增长因子指定了,那么扩容的时候每次新数组大小就会在原基础上加上增长因子;如果不指定那么就是原数组*2。
为什么ArrayList的elementData是用transient修饰
ArrayList中数组的定义:
private transient Object[] elementData;
ArrayList实现了serializable接口,这意味着ArrayList可以被序列化,用transient修饰elementData意味着我们不希望elementData数组序列化。这时为什么?因为序列化ArrayList的时候,ArrayList数组未必是满的,比如说数组大小是10,现在只有3和数组,那么是否有必要序列化整个elementData呢?显然是没有必要的,因此ArrayList重写了writeObject方法,每次序列化都调用它,先调用defaultWriteObject() 方法序列化ArrayList中非transient元素,然后遍历elementData,只序列化那些有的元素,这样:
1、加快了序列化的速度;
2、减小了序列化之后文件的大小。
- java集合系列01--ArrayList
- 【Java集合系列】---ArrayList
- JAVA学习---集合系列---ArrayList
- java集合框架系列---ArrayList
- Java集合系列之ArrayList
- java集合系列08 ArrayList
- JAVA笔记:集合系列02—ArrayList
- Java集合系列之ArrayList源码分析
- 深入Java集合系列之一:ArrayList
- Java集合系列—ArrayList详细介绍
- Java集合系列(2)--ArrayList
- java集合系列之一—ArrayList
- 集合系列之---ArrayList
- 集合系列ArrayList
- 深入Java集合学习系列:ArrayList的实现原理
- 深入Java集合学习系列:ArrayList的实现原理
- 深入Java集合学习系列:ArrayList的实现原理
- 深入Java集合学习系列:ArrayList的实现原理
- 使用Java读取Excel文件内容
- 深入理解javascript原型和闭包(13)-【作用域】和【上下文环境】
- 软件开发流程回顾
- Unity3d MVCS游戏框架Robotlegs
- Docker——常用命令(四)
- java集合系列01--ArrayList
- Android APP测试的日志文件抓取
- CJOJ 1070 【Uva】嵌套矩形
- leetcode 122. Best Time to Buy and Sell Stock II
- scala基础系列一
- 递归与分治策略之大整数的乘法
- 深入理解javascript原型和闭包(14)——从【自由变量】到【作用域链】
- [莫比乌斯反演+容斥+分块求和] BZOJ2301: [HAOI2011]Problem b
- static_cast、dynamic_cast、const_cast和reinterpret_cast总结