Android java中的ArrayList的原理和实现

来源:互联网 发布:设计模式 知乎 编辑:程序博客网 时间:2024/05/21 10:58

一、 ArrayList概述:  


    ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数返回一个线程安全的ArrayList类,也可以使用concurrent并发包下的CopyOnWriteArrayList类。


ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了Cloneable接口,能被克隆。

  1) 私有属性:

   ArrayList定义只定义类两个私有属性:


ArrayList是基于数组实现的,是一个动态数组,如下:其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。

transient Object[] elementData;/** * The size of the ArrayList (the number of elements it contains). * * @serial */private int size;


有个关键字需要解释:transient。  

  Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。

为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。

2)构造方法:构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。

public ArrayList(Collection<? extends E> c) {    elementData = c.toArray();    size = elementData.length;    // c.toArray might (incorrectly) not return Object[] (see 6260652)    if (elementData.getClass() != Object[].class)        elementData = Arrays.copyOf(elementData, size, Object[].class);}
Collection解释:类集,是一组对象。类集的增加使得许多 java.util中的成员在结构和体系结构上发生根本的改变。它也扩展了包可以被应用的任务范围。(网上查的)
集合的构造方法和固定集合的大小
List arrayList = new ArrayList(4);

3) 调整数组容量ensureCapacity: 

添加元素的时候会先判定集合的容量大小,是否需要扩容

public boolean add(E e) {    ensureCapacityInternal(size + 1);  // Increments modCount!!    elementData[size++] = e;    return true;}

   从上面介绍的向ArrayList中存储元素的代码中,我们看到,每当向数组中添加元素时,都要去检查添加后元素的个数是否会超出当前数组的长度,

如果超出,数组将会进行扩容,以满足添加数据的需求。数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。

在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。

public void ensureCapacity(int minCapacity) {    int minExpand = (elementData != EMPTY_ELEMENTDATA)        // any size if real element table        ? 0        // larger than default for empty table. It's already supposed to be        // at default size.        : DEFAULT_CAPACITY;    if (minCapacity > minExpand) {        ensureExplicitCapacity(minCapacity);    }}


数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。或者根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。

实例:

也就是说,当增加数据的时候,如果ArrayList的大小已经不满足需求时,那么就将数组变为原长度的1.5倍,之后的操作就是把老的数组拷到新的数组里面。例如,默认的数组大小是10,也就是说当我们add10个元素之后,再进行一次add时,就会发生自动扩容,数组长度由10变为了15具体情况如下所示:



总结:在用户向ArrayList追加对象时,Java总是要先计算容量(Capacity)是否适当,若容量不足则把原数组拷贝到以指定容量为长度创建的新数组内,并对原数组变量重新赋值,指向新数组。
在这同时,size进行自增1。在删除对象时,先使用拷贝方法把指定index后面的对象前移1位(如果有的话),然后把空出来的位置置null,交给Junk收集器销毁,size自减1,即完成了。

原创粉丝点击