java-collection-ArrayList

结构

这里写图片描述

这里写图片描述

特点

ArrayList是一个其容量能够动态增长的动态数组。它继承了AbstractList,实现了List、RandomAccess, Cloneable, java.io.Serializable。
基本的ArrayList,长于随机访问元素,但是在List中间插入和移除元素时较慢。同时,ArrayList的操作不是线程安全的!一般在单线程中才使用ArrayList,而在多线程中一般使用Vector或者CopyOnWriteArrayList。

List接口的可调整大小的数组实现。具有list所有操作,允许所有元素包括null.
除了执行List接口外,该类提供了方法来处理数组的大小,即内部使用来存储列表。这个类大致相等于Vector 但是不同步

size isEmpty get set iterator listiterator 操作运行在常量时间。
add操作运行在amortized constant time 也就是说 添加n个元素需要O(n)时间。所有其他操作以线性时间运行。常量因子比较低 相对LinkedList实现来说。

每个ArrayList实例具有capacity capacity用来存储列表中元素的数组的大小。
至少和list一样大。当元素被添加到数组列表中时,它的容量自动增长,

增长策略的细节 不指定 超越事实 添加一个元素有固定摊销的时间成本。

应用程序可以增长ArrayList的容量,在添加大量的元素用这个ensureCapactiy 操作,
这个可以减少增长再分配的数量 。

同步
注意此实现不同步。
如果多线程同时访问ArrayList实例,至少有一个线程在结构上修改列表,必须在外部同步。
结构修改是添加或删除一个或多个元素或显式的任何操作 调整后备数组。
仅设置元素的值不是结构修改。通常通过对一些自然封装列表的对象进行同步。
如果这样的对象不存在,list应当使用Wrapped 用 {@link Collections#synchronizedList Collections.synchronizedList}方法。最好在创建时完成,以防止意外发生。

 List list = Collections.synchronizedList(new ArrayList(...));

fail-fast

该类的Iterator和listIterator 方法 是fail-fast . 如果这个list 在任何时候修改结构 在迭代器创建之后,任何通过iterator自己的{@link ListIterator#remove() remove} or{@link ListIterator#add(Object) add}
方法,这个iterator 将会抛出{@link ConcurrentModificationException}
因此,面对并发修改,iterator 快速而干净失败,而不是在未来时间 不确定的 冒险的行为 。

注意,迭代器的故障快速行为不能得到保证,事实上,一般来说,不可能作出任何硬的保证,存在不同步的并发修改。故障快速迭代器在尽力的基础上抛出ConcurrentModificationException、
*因此,编写一个依赖于此异常正确性的程序是错误的。迭代器的fail-fast行为只用于检测缺陷。

注意

1)ArrayList是Array的复杂版本
ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于ArrayList的许多方法,如Index、IndexOf、Contains、Sort等都是在内部数组的基础上直接调用Array的对应方法。
2)内部的Object类型的影响
对于一般的引用类型来说,这部分的影响不是很大,但是对于值类型来说,往ArrayList里面添加和修改元素,都会引起装箱和拆箱的操作,频繁的操作可能会影响一部分效率。
但是恰恰对于大多数人,多数的应用都是使用值类型的数组。
消除这个影响是没有办法的,除非你不用它,否则就要承担一部分的效率损失,不过这部分的损失不会很大。
3)数组扩容
这是对ArrayList效率影响比较大的一个因素。
每当执行Add、AddRange、Insert、InsertRange等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素Copy到新数组中,然后丢弃旧数组,在这个临界点的扩容操作,应该来说是比较影响效率的。
例1:比如,一个可能有200个元素的数据动态添加到一个以默认16个元素大小创建的ArrayList中,将会经过:
16*2*2*2*2 = 256
四次的扩容才会满足最终的要求,那么如果一开始就以:
ArrayList List = new ArrayList( 210 );
的方式创建ArrayList,不仅会减少4次数组创建和Copy的操作,还会减少内存使用。

例2:预计有30个元素而创建了一个ArrayList:
ArrayList List = new ArrayList(30);
在执行过程中,加入了31个元素,那么数组会扩充到60个元素的大小,而这时候不会有新的元素再增加进来,而且有没有调用TrimSize方法,那么就有1次扩容的操作,并且浪费了29个元素大小的空间。如果这时候,用:
ArrayList List = new ArrayList(40);
那么一切都解决了。
所以说,正确的预估可能的元素,并且在适当的时候调用TrimSize方法是提高ArrayList使用效率的重要途径。

4)频繁的调用IndexOf、Contains等方法(Sort、BinarySearch等方法经过优化,不在此列)引起的效率损失

首先,我们要明确一点,ArrayList是动态数组,它不包括通过Key或者Value快速访问的算法,所以实际上调用IndexOf、Contains等方法是执行的简单的循环来查找元素,所以频繁的调用此类方法并不比你自己写循环并且稍作优化来的快,如果有这方面的要求,建议使用Hashtable或SortedList等键值对的集合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值