ArrayList详解

来源:互联网 发布:手机淘宝收藏软件 编辑:程序博客网 时间:2024/05/16 04:43

1.ArrayList简介:

ArrayList继承关系:

public class ArrayList<E> extends AbstractList<E>        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  1. ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存。

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

  3. ArrayList实现了Serializable接口,因此它支持序列化,能够通过序列化传输,实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了Cloneable接口,能被克隆。

2、ArrayList 成员变量:

序列版本号:

private static final long serialVersionUID = 8683452581122892189L;

内部结构是一个Object类型的数组:

private transient Object[] elementData;

有关键字transient修饰这个Object数组,那么ArrayList中的数据还可以通过持久化保存下来吗?
答:transient默认是不被序列化的。但是,ArrayList实现了Serializable的writeObject(),readObject()方法,实现了自己定义的持久化方式。

/**     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,     * deserialize it).     */    private void readObject(java.io.ObjectInputStream s)        throws java.io.IOException, ClassNotFoundException {    // Read in size, and any hidden stuff    s.defaultReadObject();        // Read in array length and allocate array        int arrayLength = s.readInt();        Object[] a = elementData = new Object[arrayLength];    // Read in all elements in the proper order.    for (int i=0; i<size; i++)            a[i] = s.readObject();    }

ArrayList中实际数据的数量 :

 private int size;

3、ArrayList构造函数:

1、ArrayList无参构造函数。默认容量是10 。

public ArrayList() {    this(10);    }

2、ArrayList带容量大小的构造函数

public ArrayList(int initialCapacity) {    super();        if (initialCapacity < 0)            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);    this.elementData = new Object[initialCapacity];    }

3、 创建一个包含collection的ArrayList

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);    }

4、ArrayList常用方法

1、add()方法:

    // 确定ArrarList的容量。        // 若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2 + 1”        public void ensureCapacity(int minCapacity) {            // 将“修改统计数”+1,该变量主要是用来实现fail-fast机制的            modCount++;            int oldCapacity = elementData.length;            // 若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”            if (minCapacity > oldCapacity) {                Object oldData[] = elementData;                int newCapacity = (oldCapacity * 3)/2 + 1;                //如果还不够,则直接将minCapacity设置为当前容量              if (newCapacity < minCapacity)                    newCapacity = minCapacity;                elementData = Arrays.copyOf(elementData, newCapacity);            }        }        // 添加元素e        public boolean add(E e) {            // 确定ArrayList的容量大小            ensureCapacity(size + 1);  // Increments modCount!!            // 添加e到ArrayList中            elementData[size++] = e;            return true;        }     // 将e添加到ArrayList的指定位置        public void add(int index, E element) {            if (index > size || index < 0)                throw new IndexOutOfBoundsException(                "Index: "+index+", Size: "+size);            ensureCapacity(size+1);  // Increments modCount!!            System.arraycopy(elementData, index, elementData, index + 1,                 size - index);            elementData[index] = element;            size++;        }        // 将集合c追加到ArrayList中        public boolean addAll(Collection<? extends E> c) {            Object[] a = c.toArray();            int numNew = a.length;            ensureCapacity(size + numNew);  // Increments modCount            System.arraycopy(a, 0, elementData, size, numNew);            size += numNew;            return numNew != 0;        }    

当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”

2、remove()方法:

    /**     * Removes the element at the specified position in this list.     * Shifts any subsequent elements to the left (subtracts one from their     * indices).     *     * @param index the index of the element to be removed     * @return the element that was removed from the list     * @throws IndexOutOfBoundsException {@inheritDoc}     */        public E remove(int index) {            RangeCheck(index);            modCount++;            E oldValue = (E) 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;        }   /**     * Removes the first occurrence of the specified element from this list,     * if it is present.  If the list does not contain the element, it is     * unchanged.  More formally, removes the element with the lowest index     * <tt>i</tt> such that     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>     * (if such an element exists).  Returns <tt>true</tt> if this list     * contained the specified element (or equivalently, if this list     * changed as a result of the call).     *     * @param o element to be removed from this list, if present     * @return <tt>true</tt> if this list contained the specified element     */    // 删除元素        public boolean remove(Object o) {            if (o == null) {                for (int index = 0; index < size; index++)                if (elementData[index] == null) {                    fastRemove(index);                return true;                }            } else {                // 便利ArrayList,找到“元素o”,则删除,并返回true。                for (int index = 0; index < size; index++)                if (o.equals(elementData[index])) {                    fastRemove(index);                return true;                }            }            return false;        }       

3、查找方法:

//正向查找到指定元素,返回索引public int indexOf(Object o) {    if (o == null) {        for (int i = 0; i < size; i++)        if (elementData[i]==null)            return i;    } else {        for (int i = 0; i < size; i++)        if (o.equals(elementData[i]))            return i;    }    return -1;    }
//反向查找到指定元素,返回索引public int lastIndexOf(Object o) {    if (o == null) {        for (int i = size-1; i >= 0; i--)        if (elementData[i]==null)            return i;    } else {        for (int i = size-1; i >= 0; i--)        if (o.equals(elementData[i]))            return i;    }    return -1;    }
//获得索引元素处的值public E get(int index) {    RangeCheck(index);    return (E) elementData[index];    }

4、修改方法:

public E set(int index, E element) {    RangeCheck(index);    E oldValue = (E) elementData[index];    elementData[index] = element;    return oldValue;    }

5、contains(Object o)方法:

public boolean contains(Object o) {    return indexOf(o) >= 0;    }

6、clone()方法:

public Object clone() {    try {        ArrayList<E> v = (ArrayList<E>) super.clone();        // 将当前ArrayList的全部元素拷贝到v中        v.elementData = Arrays.copyOf(elementData, size);        v.modCount = 0;        return v;    } catch (CloneNotSupportedException e) {        // this shouldn't happen, since we are Cloneable        throw new InternalError();    }    }

5、ArrayList遍历方式:

1、通过迭代器遍历。即通过Iterator去遍历。

    Integer value = null;      Iterator iter = list.iterator();      while (iter.hasNext()) {          value = (Integer)iter.next();      }  

2、 随机访问,通过索引值去遍历。由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。

    Integer value = null;      int size = list.size();      for (int i=0; i<size; i++) {          value = (Integer)list.get(i);              }  

3、for循环遍历

Integer value = null;  for (Integer integ:list) {      value = integ;  } 

6、总结:

1、注意其三个不同的构造方法。无参构造方法构造的ArrayList的容量默认为10,带有Collection参数的构造方法,将Collection转化为数组赋给ArrayList的实现数组elementData。

2、注意扩充容量的方法ensureCapacity。ArrayList在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。设置新的容量为旧的容量的1.5倍加1。

3、注意ArrayList的两个转化为静态数组的toArray方法
第一个,Object[] toArray()方法。该方法有可能会抛出java.lang.ClassCastException异常,如果直接用向下转型的方法,将整个ArrayList集合转变为指定类型的Array数组,便会抛出该异常,而如果转化为Array数组时不向下转型,而是将每个元素向下转型,则不会抛出该异常,显然对数组中的元素一个个进行向下转型,效率不高,且不太方便。

第二个, T[] toArray(T[] a)方法。该方法可以直接将ArrayList转换得到的Array进行整体向下转型(转型其实是在该方法的源码中实现的),且从该方法的源码中可以看出,参数a的大小不足时,内部会调用Arrays.copyOf方法,该方法内部创建一个新的数组返回。

5、ArrayList基于数组实现,可以通过下标索引直接查找到指定位置的元素,因此查找效率高,但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低。

6、在查找给定元素索引值等的方法中,源码都将该元素的值分为null和不为null两种情况处理,ArrayList中允许元素为null

参考资料:
Java容器类—ArrayList

0 0
原创粉丝点击