ArrayList源码学习
Posted luisyang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList源码学习相关的知识,希望对你有一定的参考价值。
可增长数组结构
实现:
1. 内部采用数组的方式。
1.1 添加元素,会每次校验容量是否满足, 扩容规则是当前数组长度+当前数组长度的二分之一。容量上限是Integer.MAX_VALUE。 copy使用Arrays.copy的api
1.2 删除元素
1.2.1 通过对象删除。遍历数组,删除第一个匹配的对象
1.2.3 通过下标删除。判断下标是否越界。
使用 System.arraycopy进行copy, 并将元素的最后一位设置为null.供gc回收
2. 内部是同步[modCount]
2.1 ArrayList数据结构变化的时候,都会将modCount++。
2.2 采用Iterator遍历的元素, next()会去检查集合是否被修改[checkForComodification],如果集合变更会抛出异常
类似于数据库层面的 乐观锁 机制。 可以通过 Iterator的api去删除元素
3. 数组结构,内部存储数据是有序的,并且数据可以为null,支持添加重复数据
modCount作用:
https://www.cnblogs.com/zuochengsi-9/p/7050351.html
源码分析
package xin.rtime.collections.list; import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchElementException; // 模拟ArrayList的实现 public class ArrayList<E> { private transient int modCount = 0; // 修改次数 private transient Object[] elementData; // 数据集合 private static final Object[] EMPTY_ELEMENTDATA = {}; // 默认空数组 private int size; // 数组实际个数 private static final int DEFAULT_CAPACITY = 10; // 默认长度 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 数组最大长度 // 默认构造函数 public ArrayList() { elementData = EMPTY_ELEMENTDATA; // 默认等于空集合 } // 初始化指定长度 public ArrayList(int initialCapacity) { if (initialCapacity < 0) // 长度小于0 抛异常 throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); this.elementData = new Object[initialCapacity]; // new一个指定长度的对象数组 } // 添加元素 public boolean add(E e) { ensureCapacityInternal(size + 1); elementData[size++] = e; // 放置添加的元素 return true; } // 删除元素 public boolean remove(E e) { if (e == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { // 删除 null fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (e.equals(elementData[index])) { // eqals比较 fastRemove(index); return true; } } return false; } private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; // 当前size - index - 1 数组从0开始 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); // system arraycopy elementData[--size] = null; // clear to let GC do its work gc回收 } public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); 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 return oldValue; } // 获取元素 public E get(int index) { rangeCheck(index); // index校验 return elementData(index); } @SuppressWarnings("unchecked") E elementData(int index) { return (E) elementData[index]; } private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private String outOfBoundsMsg(int index) { return "Index: "+index+", Size: "+size; } // 返回元素个数 public int size() { return size; } // 判断当前容量是否能否装下元素 private void ensureCapacityInternal(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) // 空集合 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); // 10 传入的 ensureExplicitCapacity(minCapacity); } // 提供外部遍历 public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { int cursor; // index of next element to return 游标 int lastRet = -1; // index of last element returned; -1 if no such 最后元素下标 int expectedModCount = modCount; // 当前数组修改次数 public boolean hasNext() { return cursor != size; // 当前游标是否等于size } @SuppressWarnings("unchecked") public E next() { checkForComodification(); // 检查数组是否被操作过 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); // 检查集合是否被操作过 try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } // 判断容量 扩容 private void ensureExplicitCapacity(int minCapacity) { modCount++; // 修改+1 if (minCapacity - elementData.length > 0) // 当前长度 大于 数组长度 grow(minCapacity); } public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } private void rangeCheckForAdd(int index) { if (index > size || index < 0) // index 超出 size 或者 index 小于0 ---> 数组越界 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } public E set(int index, E element) { rangeCheck(index); // 校验index是否满足 E oldValue = elementData(index); elementData[index] = element; return oldValue; } /** << : 左移运算符,num << 1,相当于num乘以2 >> : 右移运算符,num >> 1,相当于num除以2 >>> : 无符号右移,忽略符号位,空位都以0补齐 */ // 扩容 private void grow(int minCapacity) { int oldCapacity = elementData.length; // 当前数组长度 int newCapacity = oldCapacity + (oldCapacity >> 1); // 新容量大小 = 原来长度 + 原来长度 右移一位,除以2 if (newCapacity - minCapacity < 0) // 新长度 - 传的长度 小于 0 newCapacity = minCapacity; // if (newCapacity - MAX_ARRAY_SIZE > 0) // 当前长度超出最大容量 newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); // 拷贝原来数据 } // 判断容量 private int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } }
以上是关于ArrayList源码学习的主要内容,如果未能解决你的问题,请参考以下文章