Java7之集合类型 ArrayList与Vector

来源:互联网 发布:如何生命一个数组 编辑:程序博客网 时间:2024/05/17 03:03

转载:http://www.it165.net/pro/html/201402/9489.html

1.转载请注明出处:http://blog.csdn.net/mazhimazh/article/details/19543911

view sourceprint?
1. 

先来看ArrayList写法如下:

view sourceprint?
1.publicclass ArrayList<E> extendsAbstractList<E> implementsList<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayList 继承了AbstractList抽象类并且实现了List接口,所以提供了数组相关的添加、删除、修改、遍历等功能ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。也就是说,可以通过索引来快速获取元素对象ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆

在ArrayList中,主要是通过Object[]数组来完成实现的,与数组相比,它的容量能动态增长,这个由它自己进行管理。

1、创建ArrayList对象

来看一下构造函数:

view sourceprint?
01.// 数组缓冲区,用来存储元素
02.privatetransient Object[] elementData;// 当进行串行化时,这个属性并不会被写入
03.privateint size;                      // 数组中存储的元素个数                  
04. 
05.publicArrayList(int initialCapacity) {
06.    super();   // 
07.    if(initialCapacity < 0)
08.        thrownew IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
09.    this.elementData =new Object[initialCapacity];
10.}
11.publicArrayList() {// 默认分配的大小为10
12.    this(10);
13.}
14.// in the order they are returned by the collection's iterator.
15.publicArrayList(Collection<? extendsE> c) {
16.    elementData = c.toArray();//
17.    size = elementData.length;
18.    if(elementData.getClass() != Object[].class)
19.        elementData = Arrays.copyOf(elementData, size, Object[].class);
20.}

初始时可以指定大小,如果不指定则默认分配的大小为10。还提供了一个有Collection参数的接口,这就为List和其他的集合之间相互转换提供了便利。

2、添加元素

ArrayList中添加元素方法的实现源代码如下:

view sourceprint?
01.publicboolean add(E e) {
02.     ensureCapacityInternal(size +1);   // 保证elementData数组有足够的大小
03.     elementData[size++] = e;           // 向数组中添加新元素
04.     returntrue;
05. }
06. publicvoid add(intindex, E element) {
07.     rangeCheckForAdd(index);
08.     ensureCapacityInternal(size +1);   // 保证数组的大小
09.     // 将index索引处后的所有元素向后移动一个位置
10.     System.arraycopy(elementData, index, elementData, index +1,size - index);
11.     elementData[index] = element;      // 将新的元素添加到指定的索引处
12.     size++;                            // 元素个数加1
13. }

在添加新元素时,会改变数组的内容。所以在每次调用ensureCapacityInternal()方法进行扩容时,还会对modCount加1,这个方法及相关方法的源代码如下:

view sourceprint?
01.privatestatic final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
02. 
03.privatevoid ensureCapacityInternal(intminCapacity) {
04.    modCount++;                                        // 对modCount加1,表示数组内容发生了变化
05.    if(minCapacity - elementData.length > 0)          // 当(数组中实际元素个数+1)>数组的长度时,需要进行扩容操作
06.        grow(minCapacity);
07.}
08. 
09.privatevoid grow(intminCapacity) {
10.    intoldCapacity = elementData.length;
11.    intnewCapacity = oldCapacity + (oldCapacity >> 1); // 计算新的数组容量大小
12.    /*
13.     *  扩容后仍然小于要求的最小容量时,新数组容量大于就为最小容量大小
14.     *  扩容后新容量大于MAX_ARRAY_SIZE值时,调用hugeCapacity()进行处理
15.     */
16.    if(newCapacity - minCapacity < 0)                  
17.        newCapacity = minCapacity;
18.    if(newCapacity - MAX_ARRAY_SIZE > 0)
19.        newCapacity = hugeCapacity(minCapacity);
20.    elementData = Arrays.copyOf(elementData, newCapacity);// 将元素复制到新的数组中
21.}
22.privatestatic int hugeCapacity(int minCapacity) {
23.    if(minCapacity < 0)// overflow
24.        thrownew OutOfMemoryError();
25.    return(minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE : MAX_ARRAY_SIZE;
26.}

如上就是具体的扩容方法。

3、迭代元素

关于集合元素的迭代,在前面也说过不少了。如果不清楚,可以进行查看:

传送门: http://blog.csdn.net/mazhimazh/article/details/17759579

下面来看一个具体的例子:

view sourceprint?
01.ArrayList<String>  aList=newArrayList<String>();
02.        aList.add("a");
03.        aList.add("b");
04.        aList.add("d");
05.        ListIterator<String> it=aList.iterator();// 下面要获取到Iterator对象后添加元素,所以生成的必须是ListIterator对象
06.        // aList.add("x");      // 抛出异常ConcurrentModificationException
07.        // aList.remove(2);       // 抛出异常ConcurrentModificationException
08.        it.add("x");          // 调用自身的方法去修改正常
09.        while(it.hasNext()){
10.            System.out.print(it.next()+" ");
11.        }

程序输出的结果如下:

a b c // 注意输出结果中不含有x

可以看到,在获取了iterator实例后,aList就不可改变。当ArrayList使用了iterator()方法产生自身对应的Iterator后,只能使用Iterator自身的remove()和add()方法来修改ArrayList的结构,因为这些方法会对expectedModCount和modCount变量会自动同步,如ListItr中的add(E e)方法,如下:

view sourceprint?
01.publicvoid add(E e) {
02.      checkForComodification();
03.      try{
04.          inti = cursor;
05.          ArrayList.this.add(i, e);      // 调用ArrayList对象的add()方法进行元素的添加
06.          cursor = i +1;
07.          lastRet = -1;
08.          expectedModCount = modCount;  // 重新设置expectedModCount的值为修改后的modCount值
09.      }catch (IndexOutOfBoundsException ex) {
10.          thrownew ConcurrentModificationException();
11.      }
12.  }

还有Itr中的remove()方法,如下:

view sourceprint?
01.publicvoid remove() {
02.      if(lastRet < 0)
03.          thrownew IllegalStateException();
04.      checkForComodification();
05.      try{
06.          ArrayList.this.remove(lastRet);
07.          cursor = lastRet;
08.          lastRet = -1;
09.          expectedModCount = modCount;  // 重新设置expectedModCount值,所以在获取Itr实例时,只能通过调用这个实例中的方法进行数组内容的修改
10.      }catch (IndexOutOfBoundsException ex) {
11.          thrownew ConcurrentModificationException();
12.      }
13.  }

调用ArrayList中本身定义的添加和删除方法都会引起ConcurrentModificationException异常,因为他们并不会重新设置expectedModCount值,如下:

view sourceprint?
01.publicboolean add(E e) {
02.     ensureCapacityInternal(size +1);  // 会对modCount的值做加1操作
03.     elementData[size++] = e;
04.     returntrue;
05. }
06. publicvoid add(intindex, E element) {
07.     rangeCheckForAdd(index);
08.     ensureCapacityInternal(size +1);  // 会对modCount值做加1操作
09.     System.arraycopy(elementData, index, elementData, index +1,size - index);
10.     elementData[index] = element;
11.     size++;
12. }
13. 
14. publicE remove(int index) {
15.     rangeCheck(index);
16.     modCount++;                       // 对modCount值做加1操作
17.     E oldValue = elementData(index);
18.     intnumMoved = size - index - 1;
19.     if(numMoved > 0)
20.         System.arraycopy(elementData, index+1, elementData, index,numMoved);
21.     elementData[--size] =null;       // 有利于垃圾回收器进行回收
22.     returnoldValue;
23. }

ArrayList使用AbstractList.modCount(初始的默认值为0)作为数组内容改变的标识。在ArrayList中,凡是会引起ArrayList结构变化的方法,都会修改modCount(modCount++),以区别是否修改了ArrayList中存储的内容。

如果是对ArrayList的Iterator做修改,在Iterator中会重置expectedModCount=modCount,如上面ListIterator类中的remove()方法。这样就可以保证在生成Iterator后,只能由Iterator来修改对应的ArrayList的内容。


4、克隆ArrayList对象

view sourceprint?
01.//  克隆出ArrayList的复本,是一个深克隆(继承了Cloneable接口)
02.publicObject clone() {
03.    try{
04.        ArrayList<E> v = (ArrayList<E>)super.clone();   
05.        v.elementData = Arrays.copyOf(elementData, size);// 拷贝数组中的内容到新数组中
06.        v.modCount =0;
07.        returnv;                                         // 返回新的数组的引用
08.    }catch (CloneNotSupportedException e) {
09.        thrownew InternalError();
10.    }
11.}

进行的是深度的克隆,修改内容时不会相互影响,相当于两个完全独立的副本。

Vector类也是基于数组实现的队列,代码与ArrayList非常相似,只不过在可能发生线程安全的方法上加上了Synchorized关键字,使得其执行的效率相比ArrayList就低了。看一下两个最主要的构造函数:

view sourceprint?
01.// capacity是Vector的默认容量大小,capacityIncrement是每次Vector容量增加时的增量值。
02.publicVector(int initialCapacity, int capacityIncrement) {
03.    super();
04.    if(initialCapacity < 0)
05.        thrownew IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
06.    this.elementData =new Object[initialCapacity];
07.    this.capacityIncrement = capacityIncrement;
08.}
09.// 创建一个包含collection元素的Vector
10.publicVector(Collection<? extendsE> c) {
11.    elementData = c.toArray();
12.    elementCount = elementData.length;
13.    // c.toArray might (incorrectly) not return Object[] (see 6260652)
14.    if(elementData.getClass() != Object[].class)
15.        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
16.}




0 0
原创粉丝点击