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比较: