本文会对ArrayList
和Vector
进行分析,为何会关注这两个类,主要是由于他们拥有相同的继承结构,接下来就来探索下这两个类实现和效率的异同。java
能够看到,Vector
和ArrayList
都实现了List
和RandomAccess
接口,都继承了AbstractList
。经过他们的继承结构,大体能够猜想他们在元素的处理上存在不少相同的地方。数组
Vector
和ArrayList
都使用 Object [] elementData
保存数据,可是不一样的ArrayList
的elementData
使用transient
作了标记,这说明ArrayList
的elementData
不参与对象序列化的过程。安全
add(E)
add(int, E)
addElement(E obj)
addAll(Collection<? extends E> c)
addAll(int, Collection<? extends E> c)
insertElementAt(E obj, int )
add(E)
add(int, E)
addAll(Collection<? extends E> c)
addAll(int, Collection<? extends E> c)
在元素的添加上,Vector
和ArrayList
差很少提供了相同的接口,可是最大的不一样是Vector
提供的接口中,除了add(int, E)
以外,都是同步接口,可是add(int, E)
最终会调用同步方法insertElementAt(E obj, int )
,故Vector
添加元素都是同步方法;ArrayList
添加元素的方法都是非同步方法。bash
get(int index)
elementAt(int index)
get(int index)
在对元素的随机访问上,Vector
比ArrayList
多了一个elementAt(int index)
函数,可是elementAt(int index)
和get(int index)
原理是同样的,故能够总结为Vector
和ArrayList
在随机访问元素时实现了一样的接口。最大的不一样仍然是Vector
对元素的随机访问是同步的,而ArrayList
是非同步的。微信
ArrayList
提供了foreach
, Iterator
的遍历方式,Vector
除此以外还提供了另外两种遍历方式:多线程
Vector<String> sVector = new Vector<>();
for (int i = 0 ; i < 5 ; i++) {
sVector.add("test" + i);
}
sVector.forEach(new Consumer<String>() {
@Override
public void accept(String t) {
// TODO Auto-generated method stub
System.out.println(t);
}
});
Enumeration<String> enumeration = sVector.elements();
while (enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
复制代码
在Vector
中,这两种方式和使用Iterator
方式遍历最大的区别是他们不是同步的,主要缘由是以上两种遍历方法不会在遍历过程当中对集合中的数据进行修改。并发
因为使用数组存储元素,在元素不断的增长程中,Vector
和ArrayList
都须要对数组容量进行增长,在数组容量变化上,Vector
和ArrayList
选择了不同的策略。dom
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?capacityIncrement : oldCapacity);
.......
}
复制代码
在扩容的时候,若是capacityIncrement > 0
(caoaciryIncrement
是新建Vector
时传递的第二个参数,可是在具体使用不多使用这个参数,故大多数状况下capacityIncrement=0
),则将容量增长capacityIncrement
,不然容量直接增长一倍。ide
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
......
}
复制代码
ArrayList
的扩容很简单,直接在原来容量的基础上增长了50%。函数
Vector
是线程安全的容器,它的不少方法都使用synchronzied方法进行了修饰,说明要使用Vector实例,须要先得到锁,这一过程比较耗时,可是究竟能耗时多少,是否是比ArrayList
耗时不少?本文不打算去测试在多线程环境下二者的对比,由于在使用ArrayList
的时候,大多数场景是单线程的环境,本文就在单线程的环境中对Vector
和ArrayList
进行对比,这种对比不是精确的对比,只是对比一下快慢。本文从添加,遍历和随机访问三个方面进行对比。测量的方法比较简单,就是先向集合中添加元素,而后再去遍历元素,最后分别统计添加元素,遍历元素和随机访问的耗时,测试的java环境是jdk1.8.0_181。
long start = System.currentTimeMillis();
for (int i = 0 ; i < 500000 ; i++) {
sVector.add("qiwoo_test_add" + i);
}
long end = System.currentTimeMillis();
System.out.println("vector add time consuming:" + (end - start));
Iterator<String> iterator = sVector.iterator();
long visitStart = System.currentTimeMillis();
while (iterator.hasNext()) {
String str = iterator.next();
}
long visitEnd = System.currentTimeMillis();
System.out.println("vector visit time consuming:" + (visitEnd -visitStart));
long randAccessStart = System.currentTimeMillis();
for (int i = 0 ; i < 500000 ; i++) {
sVector.get(i);
}
long randAccessend = System.currentTimeMillis();
System.out.println("vector random access time consuming:" +(randAccessend - randAccessStart));
复制代码
在个人电脑上,运行的结果以下:
vector add time consuming:95
vector visit time consuming:18
vector random access time consuming:14
long start = System.currentTimeMillis();
for (int i = 0 ; i < 500000 ; i++) {
sArray.add("qiwoo_test_add" + i);
}
long end = System.currentTimeMillis();
System.out.println("array add time consuming:" + (end - start));
Iterator<String> iterator = sArray.iterator();
long visitStart = System.currentTimeMillis();
while (iterator.hasNext()) {
String str = iterator.next();
}
long visitEnd = System.currentTimeMillis();
System.out.println("array visit time consuming:" + (visitEnd -visitStart));
long randAccessStart = System.currentTimeMillis();
for (int i = 0 ; i < 500000 ; i++) {
sArray.get(i);
}
long randAccessend = System.currentTimeMillis();
System.out.println("array random access time consuming:" +(randAccessend - randAccessStart));
复制代码
在个人电脑上运行结果以下:
array add time consuming:82
array visit time consuming:11
array random access time consuming:5
上面的结果能够发现,在单线程环境下,在元素添加和遍历上,Vector
均比ArrayList
慢了一些,其中添加元素慢了8%左右,遍历元素慢了64%,随机访问慢了1.8倍,这些数据可能受数据量的不一样而不一样,可是总体的趋势应该是一致的。
以上测试的时候,数据量为500000,可是实际进行Android开发的过程当中产生的数据量比较少,参考下google设计容器时的数量考虑,接下来把数据量设置为1000,看下运行结果的差别
当数据量到1000时,Vector
和ArrayList
在元素的添加,遍历和随机访问上已经没有什么性能差别或者说差别很小。
ArrayList
和Vector
都是java中比较重要的容器,他们均可以存储各类对象,它们有相同的继承结构,提供大体相同的功能,主要的差别点以下:
Vector
是线程安全的容易,能够在并发环境中安全地使用,而ArrayList
是非线程安全的ArrayList
进行扩容时增长50%,Vector
提供了扩容时的增量设置,但一般将容量扩大1倍Vector
可使用Enumeration和Iterator进行元素遍历,ArrayList
只提供了Iterator的方式Vector
的效率比ArrayList
低自java1.6以后,为了优化synchronized,java引入了偏向锁,在单线程环境中,Vector
的效率已经被提升了。从刚才的对比也能够发现,在单线程环境中,数据量较少(测试数据量在100000性能差别较小)的状况下,Vector
和ArrayList
的性能差别已经不明显了。