容器扩容机制
这里以ArrayList为例
ArrayList源码分析
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {/** * 默认初始化容量 */ private static final int DEFAULT_CAPACITY = 10; /** * 空数组 */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 空数组 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 存放元素的数组 */ transient Object[] elementData; /** * 数组的元素个数 */ private int size; /** *有参构造容量大于0,一个新的对应容量的数组赋值给elementData;容量等于0,把空数组赋值给elementData;容**量小于0,抛出异常 */ public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** *无参构造初始化时候将空数组赋值给了elementData */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** *把Collection构建成ArrayList */ public ArrayList(Collection<? extends E> c) { //使用Collection的toArray()方法得到一个对象数组并赋值给elementData elementData = c.toArray(); //size是容器元素个数,所以集合转ArrayList存储时候要对size进行赋值。 if ((size = elementData.length) != 0) { // //这里是当c.toArray出错,没有返回Object[]时,利用Arrays.copyOf 来复制集合c中的元素到elementData数组中 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { //假如collection为空的话,直接给elementData一个空数组 this.elementData = EMPTY_ELEMENTDATA; } } /** * 截断多余的容量,在内存紧缺时候使用。 */ public void trimToSize() { modCount++; if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } } /** * 分配的数组最大限度。超出可能会OutOfMemoryError */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; /** * 返回元素个数 */ public int size() { return size; } /** * 判断ArrayList是否为空 */ public boolean isEmpty() { return size == 0; } /** * 判断ArrayList是否包含o */ public boolean contains(Object o) { return indexOf(o) >= 0; } /** * 如果容器中的元素有和o相等的,那么返回第一个相等元素的下标,如果没有返回-1 * 从前寻找 */ 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; } /** * ArrayList的浅拷贝 */ public Object clone() { try { ArrayList<?> v = (ArrayList<?>) super.clone(); //如果是对象的话,只会拷贝对象,不会拷贝对象的值 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(e); } } /** * ArrayList转换为数组 */ public Object[] toArray() { return Arrays.copyOf(elementData, size); } /** * ArrayList转换为指定格式的数组 * 如果ArrayList的长度大于数组a的长度,那么创建一个a类型的新数组 * 如果ArrayList的长度小于数组a的长度,那么直接把ArrayList元素复制给a,并把下标等于size元素 * 替换为null,后面的元素不动 */ @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; } /** * 查询 index角标元素 */ public E get(int index) { //越界检查 rangeCheck(index); return elementData(index); } /** * 更新index角标元素 */ public E set(int index, E element) { //越界检查 rangeCheck(index); E oldValue = elementData(index); elementData[index] = element; return oldValue; } /** * 从尾部插入元素操作 */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! //在新数组末端添加一个元素 elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private static int calculateCapacity(Object[] elementData, int minCapacity) { //假如ArrayList是通过无参构造方法创建出来的对象,如果大于10就返回元素个数,如果小于10(默认初始容量) //就返回10 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } //如果ArrayList不是通过无参构造创建出来的,那么直接返回元素个数即可 return minCapacity; } //modCount自增,如果需要扩容就进行扩容 private void ensureExplicitCapacity(int minCapacity) { modCount++; //继承自AbstractList 用来计集合修改的次数 // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } /** * 扩容1.5倍,假如还不够的话,把元素个数作为容量。 */ private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果新容量太大且超过数组最大值,如果元素个数大于数组容量最大值,那么把容量设为Integer的最大值 //如果元素个数小于数组最大值,那么把容量扩容到数组容量最大值即可 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 构建新数组 elementData = Arrays.copyOf(elementData, newCapacity); } private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** * 指定下标插入元素 */ public void add(int index, E element) { //下标越界判断 rangeCheckForAdd(index); //和尾部增加一样,判断是否需要扩容,如需则构建新数组,modCount自增 ensureCapacityInternal(size + 1); // Increments modCount!! //其他元素下标后移 System.arraycopy(elementData, index, elementData, index + 1, size - index); //把元素添加到index下标处 elementData[index] = element; //元素个数+1 size++; } /** * 判断index是否越界 */ private void rangeCheckForAdd(int index) { if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } /** * ArrayList尾部添加Collection */ public boolean addAll(Collection<? extends E> c) { //把Collection构建成数组 Object[] a = c.toArray(); int numNew = a.length; //判断是否需要扩容,如需则构建新数组,modCount自增 ensureCapacityInternal(size + numNew); // Increments modCount //把数组拷贝到原ArrayList尾部 System.arraycopy(a, 0, elementData, size, numNew); //新size size += numNew; return numNew != 0; } /** * 从下标index处插入集合c */ public boolean addAll(int index, Collection<? extends E> c) { //角标越界判断 rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount int numMoved = size - index; //index处的元素后移数组c长度个位置 if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); //把c数组插入上面移出的空位 System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; } /** * 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。 */ public void ensureCapacity(int minCapacity) { //ArrayList不是通过无参构造创建的设置minExpand为0,如果是通过无参构造创建的设置为初始容量10 int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) // any size if not default element table ? 0 // larger than default for default empty table. It's already // supposed to be at default size. : DEFAULT_CAPACITY; if (minCapacity > minExpand) { //modCound自增,进行扩容 ensureExplicitCapacity(minCapacity); } } /** * 删除对应下标的元素 */ public E remove(int index) { //判断下标是否越界 rangeCheck(index); //modCound自增 modCount++; //根据下标获取对应的元素 E oldValue = elementData(index); int numMoved = size - index - 1; //假如index对应元素不是最后一个元素,把这个元素后面的其他元素前移一位 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //把最后一位设置为默认的null元素 elementData[--size] = null; // clear to let GC do its work //返回移出的元素 return oldValue; } //根据下标获取数组对应的元素 @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; } /** * 如果ArrayList中有o元素,从ArrayList中删除第一个o元素 */ public boolean remove(Object o) { //循环数组,如果其中元素和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; } /* * modCound自增,移出index处的元素,然后后面元素前移,尾元素赋值null * 不用返回对应元素,不会越界所以不需要越界判断。 */ private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work } /** * 从ArrayList中删除Collection包含的元素 */ public boolean removeAll(Collection<?> c) { //查看Objects源码 此处如果c为空,抛出空指针异常 Objects.requireNonNull(c); return batchRemove(c, false); } /** * 从ArrayList中保留c中包含的元素 */ public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true); } private boolean batchRemove(Collection<?> c, boolean complement) { final Object[] elementData = this.elementData; int r = 0, w = 0; boolean modified = false; try { for (; r < size; r++) //complement为false,c中不包含的元素,从下标为0处放入到elementData中 //complement为true,c中包含的元素,从下标为0处放入到elementData中 if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { //由于c.contains报异常导致r!=size,把从r开始的后面项,都赋值到elementData的w项后 //即现在的elementData的w项前的元素,都是c中不包含的。w和w项后的元素还未判断,整体拿过来 if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); //把w变为elementData元素的"size"。这里的size不是实际的元素个数 //由于上面为了提高性能,没有创建新数组。而是把不被c包含的元素从开头再次存入这个数组。 //没有存放过的下标位上不是null而是以前的元素。 w += size - r; } //如果w=size,那么说明异常前,elementData的前r项都不被c包含 //此处说明有元素不被c包含 //清空上面提到的老元素 if (w != size) { // clear to let GC do its work for (int i = w; i < size; i++) elementData[i] = null; //modCount增加size-w 即从中剔除了size-w个元素 modCount += size - w; size = w; modified = true; } } return modified; } /** * 清空数组中的元素 */ public void clear() { modCount++; // clear to let GC do its work for (int i = 0; i < size; i++) elementData[i] = null; size = 0; } /** * 删除从fromIndex到toIndex(不包含)的元素 注意:继承ArrayList的类才可用 */ protected void removeRange(int fromIndex, int toIndex) { modCount++; int numMoved = size - toIndex; //把从toInDex开始的元素,复制到fromIndex---fromIndex+numMoed(不包含)处 System.arraycopy(elementData, toIndex, elementData, fromIndex, numMoved); //清空fromIndex+numMoed及后面的元素 // clear to let GC do its work int newSize = size - (toIndex-fromIndex); for (int i = newSize; i < size; i++) { elementData[i] = null; } size = newSize; } /** * 越界检查 */ private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; }/* 我们在使用List,Set的时候,为了实现对其数据的遍历,我们经常使用到了Iterator(迭代器)。使用迭代器,你不需要干涉其遍历的过程,只需要每次取出一个你想要的数据进行处理就可以了。但是在使用的时候也是有不同的。List和Set都有iterator()来取得其迭代器。对List来说,你也可以通过listIterator()取得其迭代器,两种迭代器在有些时候是不能通用的, terator和ListIterator主要区别在以下方面: 1. iterator()方法在set和list接口中都有定义,但是ListIterator()仅存在于list接口中(或实现类中); 2. ListIterator有add()方法,可以向List中添加对象,而Iterator不能 3.ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。 4. ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。 5.都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。 因为ListIterator的这些功能,可以实现对LinkedList等List数据结构的操作。其实,数组对象也可以用迭代器来实现。 */ /** * 从AbstractList继承过来的,返回当前索引位置的迭代器 */ public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } /** * 从AbstractList继承过来的,返回此列表元素的列表迭代器 */ public ListIterator<E> listIterator() { return new ListItr(0); } /** * 返回以恰当顺序在此列表的元素上进行迭代的迭代器。 */ public Iterator<E> iterator() { return new Itr(); } }
总结 :
1.底层为数组,当容量满时候进行扩容每次为1.5倍,如果还不够的话容量为元素个数。构建新数组,把原数组拷贝进新数组。
2.无参创建出来的ArrayList在第一次add时候会给一个10的容量。所以我们尽可能的在创建时候给它一个初始值,如果不确定那么用默认值
作者:刘志红
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!