zoukankan      html  css  js  c++  java
  • ArrayList详解


    ArrayList


    1.概述

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable

    • ArrayList是用数组实现的线性列表,其是相当与动态数组。
    • ArrayList查找、修改速度较快,插入、删除速度较慢。
    • ArrayList可以存放任何元素,包括null对象。
    • ArrayList是线程不同步的。

    ArrayList的类关系图如下:

     

    2.详解

    字段与构造函数

     1 private static final int DEFAULT_CAPACITY = 10;  // ArrayList默认容量
     2 transient Object[] elementData;  // ArrayList中存放元素的数组
     3 private int size;  // ArrayList存放元素的个数
     4 /**
     5  * 常量,代表ArrayList中没有元素。只有当使用有参的构造函数且initialCapatity为0时返回它。
     6  */
     7 private static final Object[] EMPTY_ELEMENTDATA = {};
     8 /**
     9  *常量,当使用无参构造函数时返回它。
    10  */
    11 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    12 /**
    13  * 默认的构造函数:创建容量为10的ArrayList
    14  */
    15 public ArrayList(){
    16     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    17 }
    18 /**
    19  * 创建一个指定容量的ArrayList
    20  * @param initialCapatity ArrayList的容量
    21  */
    22 public ArrayList(int initialCapatity){
    23     if(initialCapatity > 0) {
    24         this.elementData = new Object[initialCapatity];
    25     }else if(initialCapatity == 0) {
    26         this.elementData = EMPTY_ELEMENTDATA;
    27     }else {
    28         throw new IllegalArgumentException("Illegal Capatity" + inintCapatity);
    29     }
    30 }
    31 /**
    32  * 创建一个包含Collection的ArrayList
    33  * @param @param c Collection
    34  */
    35 public ArrayList(Collection<? extends E> c){
    36     elementData = c.toArray();
    37     if((size = elementData.length) != 0){
    38         // c.toArray might (incorrectly) not return Object[] (see 6260652)
    39         if(elementData.getClass() != Object[].class){
    40             elementData = Arrays.copyof(elementData, size, Object[].class);
    41         }
    42     }
    43 }

    一些方法

     1 public E get(int index){
     2     // 检查索引位置
     3     rangeCheck(index);
     4     return elementData[index];
     5 }
     6 public E set(int index, E element){
     7     // 检查索引位置
     8     rangeCheck(index); 
     9     E oldValue = elementData[index];
    10     elementData[index] = element;
    11     return oldValue;   
    12 }
    13 public boolean add(E e){
    14     // 确保ArrayList有足够的容量:验证+扩容
    15     ensureCapacityInternal(size + 1);
    16     elementData[size++] = e;
    17     return true;
    18 }
    19 public void add(int index, E element){
    20     // 检查索引是否合适
    21     rangeCheckForAdd(index);
    22     // 确保ArrayList有足够的容量:验证+扩容
    23     ensureCapatityInternal(size + 1);
    24     // 把原数组从index后的每一个元素向后移一位
    25     System.arraycopy(elementData,index,elementData,index+1,size-index);
    26     elementData[index] = element;
    27     size++;
    28 }
    29 public E remove(int index){
    30     // 检查索引位置是否合适
    31     rangeCheck(index);
    32     modCount++;
    33     E oldValue = elementData(index);
    34     // 把原数组从index后的每一个元素向前移动一位
    35     int numMoved = size - index - 1;
    36     if(numMoved > 0){
    37         System.arraycopy(elementData, index+1, elementData, index, numMoved);
    38     }
    39     elementData[--size] = null; //clear to let GC do its work
    40     return oldValue;
    41 }

    扩容
    在上面add()方法中我们都需要验证ArrayList容量是否足够,不足需要扩容。

     1 /**
     2  * 验证+扩容
     3  * @param minCapacity 现在ArrayList存放元素所需要的最小容量
     4  */
     5 private void ensureCapacityInternal(int minCapacity) {
     6     if(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
     7         minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
     8     }
     9     ensureExplicitCapacity(minCapacity);
    10 }
    11 private void ensureExplicitCapacity(int minCapacity) {
    12     modCount++;
    13     if(minCapacity - elementData.length > 0){
    14         // 扩容
    15         grow(minCapacity);
    16     }
    17 }
    18 /**
    19  * 该方法是扩容:扩大至原来的1.5倍,我没有看懂怎么就扩大到原来的1.5倍~(0)~
    20  */
    21 private void grow(int minCapacity) {
    22     // 扩大至原来的1.5倍
    23     int oldCapacity = elementData.length;
    24     int newCapacity = oldCapacity + (oldCapacity >> 1);
    25     if(newCapacity - minCapacity < 0){
    26         newCapacity = minCapacity;
    27     }
    28     if(newCapacity - MAX_ARRAY_SIZE > 0){
    29         newCapacity = hugeCapacity(minCapacity);
    30     }
    31     // elementData扩容
    32     elementData = Arrays.copyOf(elementData,newCapacity);
    33 }

    以上是部分源码分析。
    还有几点:

    • 以上是JDK1.8的源码,其中怎么就扩大要原来的1.5倍,我没有看懂。而且为什么要扩大要原来的1.5倍我也不知道。之前版本是增加至(oldCapacity * 3)/2 + 1。
    • 从上面我们可以看出在插入、删除元素时我们需要调用System.arraycopy()方法,这就比较耗时,所以说ArrayList在插入、删除时的速度慢的原因。当然这是由于ArrayList底层使用数组这种数据结构的缘故。

    3.自己模仿写的ArrayList

    class ArrayList<E> extends AbstractList<E> implements List<E> {
        // 默认容量
        private static final int DEFAULT_CAPACITY = 10;
        // 存放元素数量
        private int size;
        // 存放元素的数组
        private Object[] elementData;
    
        ArrayList(){
            elementData = new Object[DEFAULT_CAPACITY];
        }
    
        ArrayList(int initCapacity){
            if(initCapacity > 0){
                elementData = new Object[initCapacity];
            }else {
                throw new IllegalArgumentException("Illegal Capacity" + initCapacity);
            }
        }
    
        ArrayList(Collection< ? extends E> c){
            elementData = c.toArray();
            this.size = elementData.length;
            if(size != 0){
                if(elementData.getClass() != Object[].class){
                    elementData = copyOf(elementData,size,Object[].class);
                }
            }
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public E get(int index) {
            check(index);
            return (E) elementData[index];
        }
    
        @Override
        public int size() {
            return size;
        }
    
        @Override
        public boolean add(E e) {
            ensureCapacity(size + 1);
            elementData[size] = e;
            size++;
            return true;
        }
    
        @Override
        public void add(int index, E element) {
            check(index);
            ensureCapacity(size + 1);
            System.arraycopy(elementData,index,elementData,index+1,size - index);
            elementData[index] = element;
            size++;
        }
    
        @Override
        public boolean remove(Object o) {
            for(int index = 0; index < size; index++){
                if(Objects.equals(o,elementData[index])){
                    int numMoved = size - index - 1;
                    if(numMoved > 0){
                        System.arraycopy(elementData, index + 1, elementData, index, numMoved);
                    }
                    elementData[size] = null;
                    size--;
                    return true;
                }
            }
            return false;
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public E remove(int index) {
            check(index);
            E oldValue = (E) elementData[index];
            int numMoved = size - index - 1;
            if(numMoved > 0){
                System.arraycopy(elementData, index + 1, elementData, index, numMoved);
            }
            elementData[size] = null;
            size--;
            return oldValue;
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public E set(int index, E element) {
            check(index);
            E oldValue = (E) elementData[index];
            elementData[index] = element;
            return oldValue;
        }
    
        // 验证索引
        private void check(int index){
            if(index < 0 || index > size){
                throw new IndexOutOfBoundsException("Index:" + index + "Size:" + size);
            }
        }
        // 验证+扩容
        private void ensureCapacity(int minCapacity){
            // 验证
            if(minCapacity > elementData.length){
                // 扩容
                int oldCapacity = elementData.length;
                int newCapacity = (int) (oldCapacity * 1.5);
                elementData =  Arrays.copyOf(elementData, newCapacity);
            }
        }
    }
  • 相关阅读:
    .NET实现Excel文件的读写 未测试
    权限管理设计
    struts1中配置应用
    POJ 2139 Six Degrees of Cowvin Bacon(floyd)
    POJ 1751 Highways
    POJ 1698 Alice's Chance
    POJ 1018 Communication System
    POJ 1050 To the Max
    POJ 1002 4873279
    POJ 3084 Panic Room
  • 原文地址:https://www.cnblogs.com/maying3010/p/6484037.html
Copyright © 2011-2022 走看看