1、首先先看一下类集中Collection接口之下的实现子类继承关系
2、首先,他们的使用效果是一样的,没区别,如下所示:
- 使用ArrayList子类:
- 使用Vector子类(用的少)
- 使用LinkedList子类
3、下面详细说明一下List接口下的三个子类ArrayList、Vector、LinkedList之间的区别:
3.1、ArrayList与Vector之间的区别
1.出现版本:
Vector jdk1.0就有了;ArrayList jdk1.2才有;如图:
2.初始化容量的区别
关于容量这块儿代码中的一个常量modCount;是由AbstractList类提供的;默认大小为0;
protected transient int modCount = 0;
!!!调用无参构造的区别(初始化策略区别):就是实例化时的区别:
Vector在无参构造执行后将对象数组大小初始化为10;
ArrayList采用懒加载策略,在构造方法阶段并不初始化数组,在第一次添加元素的时候才初始化对象数组大小为10;
2.1、先看Vector的无参构造:
源码中的无参构造初始化容量为10;
public Vector() {
this(10); // initialCapacity;
}
2.2、再来看ArrayList的无参构造:
此时并没有初始化大小,只是说当前集合的数组等于 DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
而 DEFAULTCAPACITY_EMPTY_ELEMENTDATA在ArrayList中是个无法被修改的静态对象数组,数组为空;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
那么我们来看一下ArrayList中的add()方法:具体解释请看代码块,感觉在代码块中解释比较清晰;
** size的定义:**
private int size;//ArrayList类提供的私有属性,集合类的长度,没有赋值,所以默认为0;
ublic boolean add(E e) {
//此时调用 ensureCapacityInternal()这个方法,传入的参数是size+1,就是0+1;
//size的源码定义在上面代码块中有;
ensureCapacityInternal(size + 1); // Increments modCount!!
//此时的数组已经初始化好, elementData[0]=e之后下标自增;
//后面再添加元素的时候继续如此这般就行;
elementData[size++] = e;
return true;
}
//下面看一下 ensureCapacityInternal()怎么实现的;此时minCapacity=1;第一次添加元素;
private void ensureCapacityInternal(int minCapacity) {
//此处的if语句判断当前ArrayList类提供的默认对象数组elementData是否等于空,
//elementData的定义在下面代码块中
//空的话就初始化它的容量
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//关键点,此处初始化容量,初始化为DEFAULT_CAPACITY,类提供的默认值;
//DEFAULT_CAPACITY的定义在下面代码块中;
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//此时调用 ensureExplicitCapacity()方法来确定准确容量,
//此代码先不看,后面扩容区别的时候再看;
ensureExplicitCapacity(minCapacity);
}
elementData的定义
transient Object[] elementData;
DEFAULT_CAPACITY的定义
private static final int DEFAULT_CAPACITY = 10;
目前我们可以由源码看出ArrayList集合初始化的容量是10,不过是等到添加第一个元素的时候才初始化容量
3、扩容时的区别
ArrayList 扩容时,新数组大小变为原数组的1.5倍;
Vector扩容时,新数组大小变为原数组的2倍
3.1、先看Vector(2倍)是如何扩容的:看源码:
首先看一下Vector提供的add()方法源码:
public synchronized boolean add(E e) {
每添加一次,modCount就会加1,初始为0,前面说了此变量的源码
modCount++;
//然后调用ensureCapacityHelper()方法,
//其中传入的参数elementCount在Vector定义中默认为0;
//定义详情在下一个代码块
//主要讲一下此方法:
ensureCapacityHelper(elementCount + 1);
//元素赋值,下标加1,此步骤不必多说;
elementData[elementCount++] = e;
return true;
}
elementCount方法在Vector的定义:
protected int elementCount;
//此方法就是判断当前集合容量是不是满了,如果minCapacity,
//就说出前面elementCount + 1如果大于当前集合的容量了,
//就需要进入if语句,进行扩容了,扩容方法名为grow();
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
@Native public static final int MAX_VALUE = 0x7fffffff;//MAX_VALUE =2147483647;
//类中定义的属性:
protected int capacityIncrement;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//此方法为Vector扩容方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//先获取当前集合的大小
//然后心得容量直接翻倍;capacityIncrement在类中定义默认为0,
//所以此处的三目运算符就是就是 newCapacity = oldCapacity + oldCapacity;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
//下来就是判断新的容量又没有其他啥问题;
//下面这两个if语句过两天再解释,举例子解释;
if (newCapacity - minCapacity < 0)
//此处if语句想不出具体例子
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//此if语句的作用就是防止容量翻倍后超出最大允许容量;
//如果真的超出了,调用hugeCapacity()方法,
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
//此方法就是说如果扩容后会超出最大允许容量,那么就无法继续翻倍来扩容了;
if (minCapacity < 0) // overflow
//看不懂
throw new OutOfMemoryError();
//这个三目运算就是说判断需要的容量大小是否超过最大允许容量,
//超过的或就返回Integer的最大值,没超过就直接扩容为最大允许的长度(容量)
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
3.2、再来看ArrayList(1.5倍)是如何扩容的:看源码:
先看一下add方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
老样子,看它的ensureCapacityInternal()方法:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//if语句只是在初始化的时候看一下 ,我们直接跳到ensureExplicitCapacity()方法:
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity()方法:此方法中同样有modCount++;
有扩容方法grow();
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
继续,进入到grow方法里面:
与ArrayList中的grow方法只有一行代码有区别,
int newCapacity = oldCapacity + (oldCapacity >> 1);
右移一位,相当于除以2,所以说,Vector中的扩容是原始长度加上原始长度的0.5倍
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//此处是扩容1.5倍;其余的跟ArrayList中grow方法全部一样;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
4、 线程安全性;
4.1、ArrayList采用异步处理,线程不安全,效率较高;
4.2、Vector采用在方法上加锁,线程安全,效率较低;
(即便要使用线程安全的List,也不用Vector);
5、遍历上的区别
1、Vector支持较老的迭代器Enumeration;
而ArrayList不支持
2、Vector和ArrayList同时支持Iterator 、ListIterator 、foreach 输出形式
6、公共点:
底层均使用数组实现