【java源码】ArrayList
题目:【java源码】ArrayList ArrayList 常用功能:构造函数、增、批量增、删、批量删、批量保留 ArrayList 属性: // 默认数组长度(数组,而不是数据个数) 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; 1、构造函数 ①public ArrayList(); 只干了一件事:this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; ②public ArrayList(int initialCapacity); 指定初始化elementData数组的初始大小。this.elementData = new Object[initialCapacity]; ③public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } } 2、增:就是数组中插一个元素操作思路 ①public boolean add(E e); 1、确保elementData数组能够装下 首先判断原来数组长度是否为0,如果为零,那么新数组长度为Math.max(DEFAULT_CAPACITY, 加入后数组最小应该长度); 判断原来数组是否还装的下,如果需要扩容那么: private void grow(int minCapacity) { // minCapacity:加入后数组最小应该长度 // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 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); } 2、elementData[size++] = e;return true; ②public void add(int index, E element); 1、rangeCheckForAdd(index); // 检测index是否越接 if (index > size || index < 0) 2、确保elementData数组能够装下 3、System.arraycopy(elementData, index, elementData, index + 1, size - index); // 数组挪位 4、elementData[index] = element; 5、size++; 3、批量增:就是数组中插多个元素操作思路 ①public boolean addAll(Collection<? extends E> c); public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // 同上:确保elementData数组能够装下 System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; } ②public boolean addAll(int index, Collection<? extends E> c) public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // // 同上:确保elementData数组能够装下 int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; } 4、删:三点注意①按内容删,只删除第一个;②删的是equals为真的;③注意看fastRemove(index)源码 ①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; } ②public E remove(int index); // 同理 ③private void fastRemove(int index); 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 } 5、批量删、批量保留:一点注意:batchRemove方法。 ①public boolean removeAll(Collection<?> c); public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false); } ②public boolean retainAll(Collection<?> c); public boolean retainAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, true); } ③private boolean batchRemove(Collection<?> c, boolean complement); // 思想:维护两个指针。一个读指针(r),一个写指针(w)。读指针从0遍历到数组尾,在遍历中,如果符合条件就elementData[w++] = elementData[r]; 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++) if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } 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; modified = true; } } return modified; } 总结: 1、ArrayList通过内置一个Object数组实现顺序表功能。通过grow函数实现动态增长,最大长度可在源码中找答案。 2、删除功能通过fastRemove函数实现对一个删除,通过batchRemove函数实现对多个删除。通过elementData[i] = null;或elementData[--size] = null; 的方式,让JVM垃圾回收,自动回收。 private void grow(int minCapacity) { // minCapacity:加入后数组最小应该长度 // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 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 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 } 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++) if (c.contains(elementData[r]) == complement) elementData[w++] = elementData[r]; } finally { // Preserve behavioral compatibility with AbstractCollection, // even if c.contains() throws. if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } 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; modified = true; } } return modified; }