先介绍几种初始化方法
// 带初始化容量的初始化 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { // 初始话一个object 数组 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { // 初始话一个空数组 this.elementData = EMPTY_ELEMENTDATA; } else { // 抛出错误 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } // 默认初始化 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 使用一个集合初始化 public ArrayList(Collection<? extends E> c) { // 将集合转化成数组 elementData = c.toArray(); // size是arraylist的长度,赋予集合的长度 if ((size = elementData.length) != 0) { // 长度不为0, 集合转化为数组后,如果类型不是object的,转为object if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 初始化一个空数组 this.elementData = EMPTY_ELEMENTDATA; } }
重点看下c.toArray方法,假如这个集合是个arraylist类型的,那它的toArray实现如下
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
发现,调用的是Arrays.copyof方法
public static <T> T[] copyOf(T[] original, int newLength) { return (T[]) copyOf(original, newLength, original.getClass()); }
继续看
/** * * @param original 要复制的数组 * @param newLength 要复制的长度 * @param newType 要复制的数组的class类型 * @param <T> * @param <U> * @return */ public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") // 这步的作用其实是个优化,假如newType类型是一个object类型,那就直接使用new Object来进行创建数组,加入不是,就用反射的机制创建数组
// 优化的理由应该是:反射创建数组的性能为比直接创建的性能来的低 // (Object)newType == (Object)Object[].class 这句话就是判断newType是不是一个object类型 // newType.getComponentType() 其实是获得数组类型,假如说数组是一个String[],那这可以拿到String T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); // 调用本地方法,创建数组 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
再介绍ArrayList两个操作
// 移除所有在c集合里的元素 public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); return batchRemove(c, false); } // 保留所有在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 { // 根据complement判断是否保留 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. // 假如出现错误,将这个元素后面的所有元素都放到elementData中,不在做去除操作 if (r != size) { System.arraycopy(elementData, r, elementData, w, size - r); w += size - r; } // 如果没出现错误 if (w != size) { // clear to let GC do its work // 将被去除的元素置为null for (int i = w; i < size; i++) elementData[i] = null; // 修改次数 modCount += size - w; // 修改当前数组长度 size = w; // 表示做过修改 modified = true; } } return modified; }
提下java的迭代器,通过迭代器来操作ArrayList
取得迭代器
// 返回带指定游标的迭代器ListIterator public ListIterator<E> listIterator(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } // 返回游标默认为0的迭代器ListIterator public ListIterator<E> listIterator() { return new ListItr(0); } // 返回默认的迭代器Iterator public Iterator<E> iterator() { return new Itr(); }
再看下迭代器的实现
Iterator:
private class Itr implements Iterator<E> { int cursor; // 角标,下个元素的位置 int lastRet = -1; // 上次操作的元素位置 int expectedModCount = modCount; //用户操作ArrayList,会改变modCount public boolean hasNext() { return cursor != size; // 角标不为ArrayList长度,则表示有下一个 } @SuppressWarnings("unchecked") public E next() { checkForComodification(); // 检查用户是否在操作ArrayList,如果操作不在迭代 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; // 角标位置+1 return (E) elementData[lastRet = i]; // 返回当前元素 } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); // 检查用户是否在操作ArrayList,如果操作不在迭代 try { ArrayList.this.remove(lastRet); // ArrayList移除这个元素 cursor = lastRet; lastRet = -1; expectedModCount = modCount; // 重新赋予新的修改次数 } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } // 从当前角标的位置,到结束,consumer为函数编程接口,传各个元素进去执行自定义函数,若在操作过程中,ArrayList发送了修改,则退出迭代,并抛出错误 @Override @SuppressWarnings("unchecked") public void forEachRemaining(Consumer<? super E> consumer) { Objects.requireNonNull(consumer); final int size = ArrayList.this.size; int i = cursor; if (i >= size) { return; } final Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) { throw new ConcurrentModificationException(); } while (i != size && modCount == expectedModCount) { consumer.accept((E) elementData[i++]); } // update once at end of iteration to reduce heap write traffic cursor = i; lastRet = i - 1; checkForComodification(); } // 检查当前的ArrayList是否被修改 final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } }
listItr
private class ListItr extends Itr implements ListIterator<E> { // 角标设为index ListItr(int index) { super(); cursor = index; } // 判断前面是否有元素 public boolean hasPrevious() { return cursor != 0; } // 返回当前角标,就是下个元素的位置 public int nextIndex() { return cursor; } // 返回当前元素的位置 public int previousIndex() { return cursor - 1; } // 返回当前元素,并将角标改为当前元素的位置 @SuppressWarnings("unchecked") public E previous() { checkForComodification(); int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i; return (E) elementData[lastRet = i]; } // 设置当前元素的值 public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.set(lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } // 将值添加到当前元素之后 public void add(E e) { checkForComodification(); try { int i = cursor; ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
可以看出迭代器在遍历数组时,同时可以增加删除,角标都会随之发生变化。
而如果用for循环遍历ArrayList进行添加删除操作,如果不对当前位置进行一些控制,将发生一些明显的错误。在多线程的情况,操作ArrayList,你将无法知晓其它线程是否有进行添加删除操作,两方同时操作必将发生错误。
我们可以看看下面的add操作,它只是做了添加一个元素,并将size+1,而迭代器在添加的时候会进行判断modcount是否发生改变,并将角标自动+1。保证了操作的正确性。
// 添加 元素
public boolean add(E e) {
// 调整容量
ensureCapacityInternal(size + 1); // Increments modCount!!
// 赋值,并将szie+1
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 记得前面默认初始化ArrayList的时候,会将elementData赋值为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 这时候判断当前的size和DEFAULT_CAPACITY,第一次添加,size为0,所以容量将被初始化为常量10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
// 修改次数+1,如果迭代器这时候再操作元素,将抛出异常,并中断迭代
modCount++;
// 如果minCapacity的容量大于数组中元素的长度
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//newCapacity为元素长度的1.5倍
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);
}
ArrayList中还有个可分割的迭代器
//可分割迭代器 static final class ArrayListSpliterator<E> implements Spliterator<E> { //用于存放ArrayList对象 private final ArrayList<E> list; //起始位置(包含),advance/split操作时会修改 private int index; //结束位置(不包含),-1 表示到最后一个元素 private int fence; //用于存放list的modCount private int expectedModCount; ArrayListSpliterator(ArrayList<E> list, int origin, int fence, int expectedModCount) { this.list = list; this.index = origin; this.fence = fence; this.expectedModCount = expectedModCount; } //获取结束位置(存在意义:首次初始化石需对fence和expectedModCount进行赋值) private int getFence() { int hi; ArrayList<E> lst; //fence<0时(第一次初始化时,fence才会小于0): if ((hi = fence) < 0) { //list 为 null时,fence=0 if ((lst = list) == null) hi = fence = 0; else { //否则,fence = list的长度。 expectedModCount = lst.modCount; hi = fence = lst.size; } } return hi; } //分割list,返回一个新分割出的spliterator实例 // 这里要注意,index已被赋值为mid,起始位置已发生改变 public ArrayListSpliterator<E> trySplit() { //hi为当前的结束位置 //lo 为起始位置 //计算中间的位置 int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; //当lo>=mid,表示不能在分割,返回null //当lo<mid时,可分割,切割(lo,mid)出去,同时更新index=mid return (lo >= mid) ? null : new ArrayListSpliterator<E>(list, lo, index = mid, expectedModCount); } //返回true 时,只表示可能还有元素未处理 //返回false 时,没有剩余元素处理了。。。 // 注意index+1,角标向前移动了以为,下次再调用这个方法就是处理下个元素 public boolean tryAdvance(Consumer<? super E> action) { if (action == null) throw new NullPointerException(); //hi为当前的结束位置 //i 为起始位置 int hi = getFence(), i = index; //还有剩余元素未处理时 if (i < hi) { //处理i位置,index+1 index = i + 1; @SuppressWarnings("unchecked") E e = (E)list.elementData[i]; action.accept(e); //遍历时,结构发生变更,抛错 if (list.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } return false; } //顺序遍历处理所有剩下的元素 //在这个方法里,角标index不发生变化,并处理index到fence里的元素 public void forEachRemaining(Consumer<? super E> action) { int i, hi, mc; // hoist accesses and checks from loop ArrayList<E> lst; Object[] a; if (action == null) throw new NullPointerException(); if ((lst = list) != null && (a = lst.elementData) != null) { //当fence<0时,表示fence和expectedModCount未初始化 if ((hi = fence) < 0) { /// 注意hi在这里被赋值 mc = lst.modCount; hi = lst.size; } else mc = expectedModCount; if ((i = index) >= 0 && (index = hi) <= a.length) { for (; i < hi; ++i) { @SuppressWarnings("unchecked") E e = (E) a[i]; //调用action.accept处理元素 action.accept(e); } //遍历时发生结构变更时抛出异常 if (lst.modCount == mc) return; } } throw new ConcurrentModificationException(); } // 返回剩下元素长度 public long estimateSize() { return (long) (getFence() - index); } public int characteristics() { //打上特征值:、可以返回size return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; } }
使用下这个ArrayList的可分割迭代器
public static void main(String[] args) throws IOException, ClassNotFoundException { List<String> arrs = new ArrayList<>(); arrs.add("a"); arrs.add("b"); arrs.add("c"); arrs.add("d"); arrs.add("e"); arrs.add("f"); arrs.add("h"); arrs.add("i"); arrs.add("j"); Spliterator<String> a = arrs.spliterator(); //运行到这里,结果:a:0-9(index-fence) Spliterator<String> b = a.trySplit(); //运行到这里,结果:a:4-9 b:0-4 Spliterator<String> c = a.trySplit(); //运行到这里,结果:a:6-9 b:0-4 c:4-6 }
注意,这个分割都是从index到fence,fence一般为迭代器里最大操作位置,index为当前操作的位置,如果操作了第一个元素,比如使用了tryAdvance。那index+1,则分割的时候,也是index到(index+fence)/2;分割出去。
public static void main(String[] args) throws IOException, ClassNotFoundException { List<String> arrs = new ArrayList<>(); arrs.add("a"); arrs.add("b"); arrs.add("c"); arrs.add("d"); arrs.add("e"); arrs.add("f"); arrs.add("h"); arrs.add("i"); arrs.add("j"); Spliterator<String> a = arrs.spliterator(); //运行到这里,结果:a:0-9(index-fence) Consumer<String> t = (inputStr) -> {System.out.println(inputStr.equals("a") ? "的确为a":"不是a啊");}; a.tryAdvance(t); //运行到这里,输出:的确为a Spliterator<String> b = a.trySplit(); //运行到这里,结果:a:5-9 b:1-5 Spliterator<String> c = a.trySplit(); //运行到这里,结果:a:7-9 b:1-5 c:5-7 }