1. ArrayList 是线程不安全的,Vector 是线程安全的
Vector
类的所有方法都是同步的。可以有两个线程安全的访问一个Vector
对象,但是一个线程访问Vector
的话会在同步操作上耗费大量的时间。ArrayList
是线程不安全的,所以当我们不需要保证线程安全性的时候推荐使用ArrayList
,如果想要在多线程中使用ArrayList
可以通过Collections.synchronizedList(new ArrayList())
或new CopyOnWriteArrayList
的方式创建一个线程安全的ArrayList
集合
2. ArrayList 使用默认构造器创建对象时是在调用 add()
方法时对 ArrayList 的默认容量进行初始化的,Vector 在调用构造器时就对容量进行了初始化
首先对比 ArrayList 和 Vector 的无参构造函数
// ArrayList 的无参构造函数
public ArrayList() {
// 默认为一个空对象数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// Vector 无参构造函数
public Vector() {
this(10);
}
// 调用的 Vector 有参构造函数
// initialCapacity 为 10,capacityIncrement 没传入默认为 0
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
// 初始化对象数组大小,对象数组大小为
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
再看看 ArrayList 和 Vector 添加操作 add() 的源码
// ArrayList 的添加方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// ArrayList 在执行 add() 方法时才将对象数组进行赋值
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
// Vector 的添加方法
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
3. ArrayList 存储数据的 Object 数组使用了 transient
关键字,Vector 的 Object 数组没有
transient
解释:
transient
:Java 语言的关键字,变量修饰符,如果用transient
声明一个实例变量,当对象存储时,它的值不需要维持。这里的对象存储是指,Java 的 serialization 提供的一种持久化对象实例的机制。当一个对象被序列化的时候,transient
型变量的值不包括在序列化的表示中,然而非transient
型的变量是被包括进去的。使用情况是:当持久化对象时,可能有一个特殊的对象数据成员,我们不想用 serialization 机制来保存它。为了在一个特定对象的一个域上关闭 serialization,可以在这个域前加上关键字transient
。
简单的说,就是被
transient
修饰的成员变量,在序列化的时候其值会被忽略,在被反序列化后,transient
变量的值被设为初始值, 如int
型的是 0,对象型的是null
。
4. ArrayList 和 Vector 的扩容机制不同
ArrayList 扩容源代码
private void grow(int minCapacity) {
// 获取当前数组的长度
int oldCapacity = elementData.length;
// 在原数组的基础上 扩容 1.5 倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 扩容后的数组不能满足最小需求容量 数组扩容为最小需求容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 数组扩容后大于 最大数组长度 将数组最大长度设置为 Integer 的最大值,2^31-1
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将数组进行复制扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
Vector 扩容源代码
private void grow(int minCapacity) {
// 获取当前容器的长度
int oldCapacity = elementData.length;
// 若容器增量大于 0 则 扩容 (容器增量 + 原容器长度) 当我们不通过构造器指定 capacityIncrement 时默认容器增量为 0。容器增量不大于 0 时按 2 倍容器大小扩容
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
// 容器扩容后仍不满足需求,扩容为最小需求容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 容器扩容后大于 最大数组长度时 与 ArrayList 操作相同
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将数组进行复制扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}