Java7之集合类型 ArrayList与Vector
转载自:http://www.it165.net/pro/html/201402/9489.html
先来看ArrayList写法如下:
1.
public
class
ArrayList<E>
extends
AbstractList<E>
implements
List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList 继承了AbstractList抽象类并且实现了List接口,所以提供了数组相关的添加、删除、修改、遍历等功能ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。也就是说,可以通过索引来快速获取元素对象ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆
在ArrayList中,主要是通过Object[]数组来完成实现的,与数组相比,它的容量能动态增长,这个由它自己进行管理。
1、创建ArrayList对象
来看一下构造函数:
01.
// 数组缓冲区,用来存储元素
02.
private
transient
Object[] elementData;
// 当进行串行化时,这个属性并不会被写入
03.
private
int
size;
// 数组中存储的元素个数
04.
05.
public
ArrayList(
int
initialCapacity) {
06.
super
();
//
07.
if
(initialCapacity <
0
)
08.
throw
new
IllegalArgumentException(
"Illegal Capacity: "
+ initialCapacity);
09.
this
.elementData =
new
Object[initialCapacity];
10.
}
11.
public
ArrayList() {
// 默认分配的大小为10
12.
this
(
10
);
13.
}
14.
// in the order they are returned by the collection's iterator.
15.
public
ArrayList(Collection<?
extends
E> 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中添加元素方法的实现源代码如下:
01.
public
boolean
add(E e) {
02.
ensureCapacityInternal(size +
1
);
// 保证elementData数组有足够的大小
03.
elementData[size++] = e;
// 向数组中添加新元素
04.
return
true
;
05.
}
06.
public
void
add(
int
index, 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,这个方法及相关方法的源代码如下:
01.
private
static
final
int
MAX_ARRAY_SIZE = Integer.MAX_VALUE -
8
;
02.
03.
private
void
ensureCapacityInternal(
int
minCapacity) {
04.
modCount++;
// 对modCount加1,表示数组内容发生了变化
05.
if
(minCapacity - elementData.length >
0
)
// 当(数组中实际元素个数+1)>数组的长度时,需要进行扩容操作
06.
grow(minCapacity);
07.
}
08.
09.
private
void
grow(
int
minCapacity) {
10.
int
oldCapacity = elementData.length;
11.
int
newCapacity = 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.
private
static
int
hugeCapacity(
int
minCapacity) {
23.
if
(minCapacity <
0
)
// overflow
24.
throw
new
OutOfMemoryError();
25.
return
(minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE : MAX_ARRAY_SIZE;
26.
}
如上就是具体的扩容方法。
3、迭代元素
关于集合元素的迭代,在前面也说过不少了。如果不清楚,可以进行查看:
传送门: http://blog.csdn.net/mazhimazh/article/details/17759579
下面来看一个具体的例子:
01.
ArrayList<String> aList=
new
ArrayList<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)方法,如下:
01.
public
void
add(E e) {
02.
checkForComodification();
03.
try
{
04.
int
i = 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.
throw
new
ConcurrentModificationException();
11.
}
12.
}
还有Itr中的remove()方法,如下:
01.
public
void
remove() {
02.
if
(lastRet <
0
)
03.
throw
new
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.
throw
new
ConcurrentModificationException();
12.
}
13.
}
调用ArrayList中本身定义的添加和删除方法都会引起ConcurrentModificationException异常,因为他们并不会重新设置expectedModCount值,如下:
01.
public
boolean
add(E e) {
02.
ensureCapacityInternal(size +
1
);
// 会对modCount的值做加1操作
03.
elementData[size++] = e;
04.
return
true
;
05.
}
06.
public
void
add(
int
index, 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.
public
E remove(
int
index) {
15.
rangeCheck(index);
16.
modCount++;
// 对modCount值做加1操作
17.
E oldValue = elementData(index);
18.
int
numMoved = size - index -
1
;
19.
if
(numMoved >
0
)
20.
System.arraycopy(elementData, index+
1
, elementData, index,numMoved);
21.
elementData[--size] =
null
;
// 有利于垃圾回收器进行回收
22.
return
oldValue;
23.
}
ArrayList使用AbstractList.modCount(初始的默认值为0)作为数组内容改变的标识。在ArrayList中,凡是会引起ArrayList结构变化的方法,都会修改modCount(modCount++),以区别是否修改了ArrayList中存储的内容。
如果是对ArrayList的Iterator做修改,在Iterator中会重置expectedModCount=modCount,如上面ListIterator类中的remove()方法。这样就可以保证在生成Iterator后,只能由Iterator来修改对应的ArrayList的内容。
4、克隆ArrayList对象
01.
// 克隆出ArrayList的复本,是一个深克隆(继承了Cloneable接口)
02.
public
Object clone() {
03.
try
{
04.
ArrayList<E> v = (ArrayList<E>)
super
.clone();
05.
v.elementData = Arrays.copyOf(elementData, size);
// 拷贝数组中的内容到新数组中
06.
v.modCount =
0
;
07.
return
v;
// 返回新的数组的引用
08.
}
catch
(CloneNotSupportedException e) {
09.
throw
new
InternalError();
10.
}
11.
}
进行的是深度的克隆,修改内容时不会相互影响,相当于两个完全独立的副本。
Vector类也是基于数组实现的队列,代码与ArrayList非常相似,只不过在可能发生线程安全的方法上加上了Synchorized关键字,使得其执行的效率相比ArrayList就低了。看一下两个最主要的构造函数:
01.
// capacity是Vector的默认容量大小,capacityIncrement是每次Vector容量增加时的增量值。
02.
public
Vector(
int
initialCapacity,
int
capacityIncrement) {
03.
super
();
04.
if
(initialCapacity <
0
)
05.
throw
new
IllegalArgumentException(
"Illegal Capacity: "
+ initialCapacity);
06.
this
.elementData =
new
Object[initialCapacity];
07.
this
.capacityIncrement = capacityIncrement;
08.
}
09.
// 创建一个包含collection元素的Vector
10.
public
Vector(Collection<?
extends
E> 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.
}