【烟火气】从面试题学技术-ArrayList 和 Vector 的区别
ArrayList 和 Vector 的区别
- 问题本质
Java集合的理解
- 问题解释
首先,我们来看看集合的类图。
其中vector这个集合类现在已经很少用了,但是面试题中还可能遇到。我们的学习重点,应该几种在ArrayList,linkedlist,hashset和treeset上。
接下来我们详细介绍一下ArrayList和vector,以后有机会再详细介绍其他接口。
我么能看到,这俩接口都是继承自list的。所以我们可以对比着学。
二者的实现大致相同,只是vector在ArrayList的基础上添加了线程安全关键字来约束。当执行synchronized修饰的方法前,系统会对该方法加一把锁,方法执行完成后释放锁。所以ArrayList的效率比较高,vector的安全性比较高。
- ArrayList
我们先来看看它的源码:
首先,它是基于数组实现的(elementData),并且实现了list接口。
例如,下面的add和remove方法,我们可以使用他们来和vector来进行对比。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable { transient Object[] elementData; private int size;
} |
private void add(E e, Object[] elementData, int s) { if (s == elementData.length) { elementData = this.grow(); } elementData[s] = e; this.size = s + 1; } public boolean add(E e) { ++this.modCount; this.add(e, this.elementData, this.size); return true; } |
public E remove(int index) { Objects.checkIndex(index, this.size); Object[] es = this.elementData; E oldValue = es[index]; this.fastRemove(es, index); return oldValue; } |
- Vector
我们首先看一下它的源码:
首先,它是基于数组实现的(elementData),并且实现了list接口,而且使用synchronized进行线程安全保证,这个可以在所有重要的方法中得到体现。
例如,下面的add和remove方法,可以看到,对外的接口使用synchronized进行修饰,保证线程安全。
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable { protected Object[] elementData; protected int elementCount; } |
private void add(E e, Object[] elementData, int s) { if (s == elementData.length) { elementData = this.grow(); } elementData[s] = e; this.elementCount = s + 1; } public synchronized boolean add(E e) { ++this.modCount; this.add(e, this.elementData, this.elementCount); return true; } |
public synchronized E remove(int index) { ++this.modCount; if (index >= this.elementCount) { throw new ArrayIndexOutOfBoundsException(index); } else { E oldValue = this.elementData(index); int numMoved = this.elementCount - index - 1; if (numMoved > 0) { System.arraycopy(this.elementData, index + 1, this.elementData, index, numMoved); } this.elementData[--this.elementCount] = null; return oldValue; } } |
- 区别
- Vector是线程安全的,ArrayList是线程不安全的(多了个synchronized)
- ArrayList在底层数组不够的时候,在原基础上扩充0.5倍,而vector扩充1倍。
- 延伸
- 那么问题来了,为什么ArrayList线程不安全,怎么办?为什么大家不用vector呢?
原因大致有这么几个,因为线程安全,牺牲了效率;扩容的时候扩一倍,牺牲了空间;分配内存时容易失败;尾部增删,效率低。
- 那么,如果用ArrayList又需要线程安全怎么办?
我们可以加上Collections.synchronizedList,它会自动将我们的list方法进行改变,最后返回给我们一个加锁了List
static List<Object> arrayListSafe2 = Collections.synchronizedList(new ArrayList<Object>()); |
那么,既然有ArrayList的线程安全同步方法,又有什么理由去使用vector呢?
- 其实和ArrayList以及Vector方法形式的类还有,hashmap ,hashtable 以及stringbuild,stringbuffer。后者都是前者的基础上增加了线程安全的实现。