您的位置:首页 > 编程语言 > Java开发

Java7之集合类型 ArrayList与Vector

2015-01-12 13:50 381 查看
Java7之集合类型ArrayList与Vector

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

先来看ArrayList写法如下:

viewsourceprint?

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对象

来看一下构造函数:

viewsourceprint?

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(
"IllegalCapacity:"
+initialCapacity);

09.
this
.elementData=
new
Object[initialCapacity];

10.
}

11.
public

ArrayList(){
//默认分配的大小为10

12.
this
(
10
);

13.
}

14.
//intheordertheyarereturnedbythecollection'siterator.

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中添加元素方法的实现源代码如下:

viewsourceprint?

01.
public

boolean
add(Ee){

02.
ensureCapacityInternal(size+
1
);
//保证elementData数组有足够的大小

03.
elementData[size++]=e;
//向数组中添加新元素

04.
return

true
;

05.
}

06.
public

void
add(
int

index,Eelement){

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,这个方法及相关方法的源代码如下:

viewsourceprint?

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
下面来看一个具体的例子:

viewsourceprint?

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.
}


程序输出的结果如下:

abc//注意输出结果中不含有x

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

viewsourceprint?

01.
public

void
add(Ee){

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
(IndexOutOfBoundsExceptionex){

10.
throw

new
ConcurrentModificationException();

11.
}

12.
}


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

viewsourceprint?

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
(IndexOutOfBoundsExceptionex){

11.
throw

new
ConcurrentModificationException();

12.
}

13.
}


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

viewsourceprint?

01.
public

boolean
add(Ee){

02.
ensureCapacityInternal(size+
1
);
//会对modCount的值做加1操作

03.
elementData[size++]=e;

04.
return

true
;

05.
}

06.
public

void
add(
int

index,Eelement){

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

Eremove(
int

index){

15.
rangeCheck(index);

16.
modCount++;
//对modCount值做加1操作

17.
EoldValue=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对象

viewsourceprint?

01.
//克隆出ArrayList的复本,是一个深克隆(继承了Cloneable接口)

02.
public

Objectclone(){

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
(CloneNotSupportedExceptione){

09.
throw

new
InternalError();

10.
}

11.
}


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

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

viewsourceprint?

01.
//capacity是Vector的默认容量大小,capacityIncrement是每次Vector容量增加时的增量值。

02.
public

Vector(
int

initialCapacity,
int
capacityIncrement){

03.
super
();

04.
if

(initialCapacity<
0
)

05.
throw

new
IllegalArgumentException(
"IllegalCapacity:"
+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.toArraymight(incorrectly)notreturnObject[](see6260652)

14.
if

(elementData.getClass()!=Object[].
class
)

15.
elementData=Arrays.copyOf(elementData,elementCount,Object[].
class
);

16.
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: