博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java中ArrayList实现原理
阅读量:6180 次
发布时间:2019-06-21

本文共 6433 字,大约阅读时间需要 21 分钟。

简述:

  • ArrayList可以理解为动态数组,与Java中的数组相比,它的容量能动态增长。超出限制时会增加50%容量,用System.arraycopy()复制到新的数组中,因此最好能给出数组大小的预估值;
  • 容量大小也可以在程序中通过ensureCapacity(int minCapacity)方法来调整;
  • 默认第一次插入元素时创建大小为10的数组(注意,是在插入元素时,而不是new ArrayList时);
  • ArrayList继承了AbstractList,实现了List;实现了RandomAccess接口,即提供了随机访问功能;实现了Cloneable接口,覆盖了clone()方法,能被克隆;实现了Serializable接口,支持序列化;

数据结构:

  使用Object数组实现

1   /**2      * The array buffer into which the elements of the ArrayList are stored.3      * The capacity of the ArrayList is the length of this array buffer. Any4      * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA5      * will be expanded to DEFAULT_CAPACITY when the first element is added.6      */7     transient Object[] elementData; // non-private to simplify nested class access

构造方法:

  提供了三种方式的构造器:

  1. public ArrayList() 可以构造一个空列表;
  2. public ArrayList(int initialCapacity) 构造一个指定初始容量的空列表;
  3. public ArrayList(Collection<? extends E> c) 构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列;
1 /** 2      * Constructs an empty list with the specified initial capacity. 3      * @param  initialCapacity  the initial capacity of the list 4      * @throws IllegalArgumentException if the specified initial capacity 5      *         is negative 6      */ 7     public ArrayList(int initialCapacity) { 8         if (initialCapacity > 0) { 9             this.elementData = new Object[initialCapacity];10         } else if (initialCapacity == 0) {11             this.elementData = EMPTY_ELEMENTDATA;12         } else {13             throw new IllegalArgumentException("Illegal Capacity: "+14                                                initialCapacity);15         }16     }17     /**18      * Constructs an empty list with an initial capacity of ten.19      */20     public ArrayList() {21         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;22     }23     /**24      * Constructs a list containing the elements of the specified25      * collection, in the order they are returned by the collection's26      * iterator.27      * @param c the collection whose elements are to be placed into this list28      * @throws NullPointerException if the specified collection is null29      */30     public ArrayList(Collection
c) {31 elementData = c.toArray();32 if ((size = elementData.length) != 0) {33 // c.toArray might (incorrectly) not return Object[] (see 6260652)34 if (elementData.getClass() != Object[].class)35 elementData = Arrays.copyOf(elementData, size, Object[].class);36 } else {37 // replace with empty array.38 this.elementData = EMPTY_ELEMENTDATA;39 }40 }
View Code

存储:

  1.set(int index, E element)

  该方法首先通过rangeCheck(index)来校验index变量是否超出数组范围,超出则抛出异常。然后取出原index位置的值作为oldValue,并将新的element放入index位置,最后返回oldValue。

1   public E set(int index, E element) { 2         rangeCheck(index); 3         E oldValue = elementData(index); 4         elementData[index] = element; 5         return oldValue; 6     } 7     private void rangeCheck(int index) { 8         if (index >= size) 9             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));10     }11     E elementData(int index) {12         return (E) elementData[index];13     }

  2.add(E e)

  该方法是将指定的元素添加到列表的尾部。首先判断list是否需要扩容,然后再将元素添加到数组中。

1   public boolean add(E e) { 2         ensureCapacityInternal(size + 1);  // Increments modCount!! 3         elementData[size++] = e; 4         return true; 5     } 6     private void ensureCapacityInternal(int minCapacity) { 7         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 8             minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 9         }10         ensureExplicitCapacity(minCapacity);11     }12     private void ensureExplicitCapacity(int minCapacity) {13         modCount++;14         // overflow-conscious code15         if (minCapacity - elementData.length > 0)16             grow(minCapacity);17     }18     private void grow(int minCapacity) {19         // overflow-conscious code20         int oldCapacity = elementData.length;21         // 扩展为原来size的1.5倍大小22         int newCapacity = oldCapacity + (oldCapacity >> 1);23         // 如果扩为1.5倍大小仍不能满足需求,则直接扩为需求值(minCapacity)24         if (newCapacity - minCapacity < 0)25             newCapacity = minCapacity;26         if (newCapacity - MAX_ARRAY_SIZE > 0)27             newCapacity = hugeCapacity(minCapacity);28         // minCapacity is usually close to size, so this is a win:29         elementData = Arrays.copyOf(elementData, newCapacity);30     }31     private static int hugeCapacity(int minCapacity) {32         if (minCapacity < 0) // overflow33             throw new OutOfMemoryError();34         return (minCapacity > MAX_ARRAY_SIZE) ?35             Integer.MAX_VALUE :36             MAX_ARRAY_SIZE;37     }

删除:

  ArrayList提供了根据下标或者指定对象两种方式的删除功能:

  1.public E remove(int index)

1     public E remove(int index) { 2         rangeCheck(index); 3         modCount++; 4         E oldValue = elementData(index); 5         int numMoved = size - index - 1; 6         if (numMoved > 0) 7             System.arraycopy(elementData, index+1, elementData, index, 8                              numMoved); 9         elementData[--size] = null; // clear to let GC do its work10         return oldValue;11     }

  2.public boolean remove(Object o)

public boolean remove(Object o) {        if (o == null) {            for (int index = 0; index < size; index++)                if (elementData[index] == null) {                    fastRemove(index);                    return true;                }        } else {            for (int index = 0; index < size; index++)                if (o.equals(elementData[index])) {                    fastRemove(index);                    return true;                }        }        return false;    }

读取:

  1.get(int index)

  该方法会判断输入的index是否越界,然后将数组的index位置的元素返回即可。

1     public E get(int index) {2         rangeCheck(index);3         return elementData(index);4     }5     private void rangeCheck(int index) {6         if (index >= size)7             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));8     }

扩容:

  扩容代码上边提到过,不再赘述。

  数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长是原容量的1.5倍。

  这种操作的代价还是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。

  如果我们可预知要保存的元素是多少时,要在构造ArrayList实例时,就指定其容量,以避免数组扩容的发生。

  或者根据实际需求,在程序中通过调用ensureCapacity(int minCapacity)方法来手动调整ArrayList实例的容量,如想调整容量的增长策略,可继承ArrayList,并覆盖ensureCapacity方法。

转载地址:http://aebda.baihongyu.com/

你可能感兴趣的文章
深入理解Java8 Lambda表达式
查看>>
Java集合框架面试问题集锦
查看>>
Java每天10道面试题,跟我走,offer有!(六)
查看>>
四种途径提高RabbitMQ传输数据的可靠性(二)
查看>>
c语言实现多态
查看>>
Linux 在 TOP 命令中切换内存的显示单位
查看>>
浏览器的加载与页面性能优化
查看>>
Java基础学习总结(5)——多态
查看>>
shell: demo
查看>>
使用vc+如何添加特殊字符的控件(创世纪篇)
查看>>
Linux下的常用信号
查看>>
3.UIImageView+category
查看>>
2.UIView+category
查看>>
Android ImageLoader使用
查看>>
LDTP
查看>>
StringUtils工具类的常用方法
查看>>
linux下VNC安装与配置
查看>>
URL编码
查看>>
光模块及光纤知识(含分类,常用类型介绍)
查看>>
Apache 单IP多端口设置
查看>>