java集合之深入分析ArrayList
ArrayList特点:
ArrayList方法实现:
扩容方法的实现:
源码:
1 private void ensureCapacityInternal(int minCapacity) { 2 //如果数组为默认大小,则扩大的容量为minCapacity和默认值两个值的较大者 3 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 4 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 5 } 6 7 ensureExplicitCapacity(minCapacity); 8 }
1 private void ensureExplicitCapacity(int minCapacity) { 2 modCount++; 3 4 // overflow-conscious code 5 //如果要扩大的容量比当前的数组长度大,则对数组进行扩容 6 if (minCapacity - elementData.length > 0) 7 grow(minCapacity); 8 }
1 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; 2 3 /** 4 * Increases the capacity to ensure that it can hold at least the 5 * number of elements specified by the minimum capacity argument. 6 * 7 * @param minCapacity the desired minimum capacity 8 */ 9 private void grow(int minCapacity) { 10 // overflow-conscious code 11 int oldCapacity = elementData.length; 12 //增加的容量为原来大小的一半 13 int newCapacity = oldCapacity + (oldCapacity >> 1); 14 //如果增加了一半的容量还比要扩容的数量小,则新数组的大小为要扩容的数量 15 if (newCapacity - minCapacity < 0) 16 newCapacity = minCapacity; 17 //如果新数组的大小大于Integer.MAX_VALUE - 8,则进行判断 18 if (newCapacity - MAX_ARRAY_SIZE > 0) 19 newCapacity = hugeCapacity(minCapacity); 20 // minCapacity is usually close to size, so this is a win: 21 //将原数组的元素全部复制到新数组中 22 elementData = Arrays.copyOf(elementData, newCapacity); 23 } 24 25 private static int hugeCapacity(int minCapacity) { 26 //如果minCapacity < 0,则容量值溢出 27 if (minCapacity < 0) // overflow 28 throw new OutOfMemoryError(); 29 30 return (minCapacity > MAX_ARRAY_SIZE) ? 31 Integer.MAX_VALUE : 32 MAX_ARRAY_SIZE;//Integer.MAX_VALUE - 8 33 }
clone方法分析:
ArrayList中的clone()方法为浅克隆,克隆后的集合对象与原有的集合对象不是同一个对象(即,指向不同的内存空间),但是它们集合元素引用的对象都是相同的。
源码:
1 public Object clone() { 2 try { 3 ArrayList<?> v = (ArrayList<?>) super.clone(); 4 //重新分配了一个链表,但是里面的元素是复制的引用(浅克隆) 5 v.elementData = Arrays.copyOf(elementData, size); 6 v.modCount = 0; 7 return v; 8 } catch (CloneNotSupportedException e) { 9 // this shouldn't happen, since we are Cloneable 10 throw new InternalError(e); 11 } 12 }
示例程序:
ArrayList<String> list = new ArrayList<>(); //这样加入集合中时,引用的对象在常量池中 // list.add("dongfangbubai"); // String string = "dongfangbubai"; ////这样加入集合中时,引用的对象堆中 String string = new String("dongfangbubai"); list.add(string); list.add("shangshanruoshui"); ArrayList listClone = (ArrayList) list.clone(); System.out.println(listClone); String content = "dongfangbubai"; System.out.println(list.get(0).equals(content)); System.out.println(list.get(0) == content); //克隆前后两个集合对应的元素所引用的都是同一个对象,true System.out.println(list.get(0) == listClone.get(0)); //克隆前后两个集合是不同的集合,false System.out.println(list == listClone);
ArrayList迭代时用迭代器只能一次删除一个元素(在一个迭代循环里),否则会出现java.lang.IllegalStateException异常。从源码可以看出这一点。
1 public void remove() { 2 if (lastRet < 0) 3 throw new IllegalStateException(); 4 checkForComodification(); 5 6 try { 7 ArrayList.this.remove(lastRet); 8 9 cursor = lastRet; 10 //进行一次删除操作时,随即就把lastRet置为一,每次迭代时就把迭代的元素索引赋个给astRet 11 lastRet = -1; 12 expectedModCount = modCount; 13 } catch (IndexOutOfBoundsException ex) { 14 throw new ConcurrentModificationException(); 15 } 16 }
// 数据结构发生改变,和fail-fast机制有关,在使用迭代器过程中,只能通过迭代器的方法(比如迭代器中add,remove等),修改List的数据结构, // 如果使用List的方法(比如List中的add,remove等),修改List的数据结构,会抛出ConcurrentModificationException
fail-fast机制的实现
fail-fast机制也叫作”快速失败”机制,是java集合中的一种错误检测机制。
在对集合进行迭代过程中,除了迭代器可以对集合进行数据结构上进行修改(迭代器进行结构修改时不会增加modCount值),其他的对集合的数据结构进行修改,都会抛出ConcurrentModificationException错误。
这里,所谓的进行数据结构上进行修改
,是指对存储的对象,进行add,set,remove操作,进而对数据发生改变。
ArrayList中,有个modCount的变量,每次进行add,set,remove等操作,都会执行modCount++。
在获取ArrayList的迭代器时,会将ArrayList中的modCount保存在迭代中,
每次执行add,set,remove等操作,都会执行一次检查,调用checkForComodification方法,对modCount进行比较。
如果迭代器中的modCount和List中的modCount不同,则抛出ConcurrentModificationException
源码:源码中modCount在list中,
expectedModCount是在迭代时传入的modCount值,若迭代过程中list结构改变时,modCount会增加,以此迭代器1来判断迭代时list是否变化。
1 final void checkForComodification() { 2 if (modCount != expectedModCount) 3 throw new ConcurrentModificationException(); 4 }
ArrayList与vector比较: