集合框架中List接口下的三个子类ArrayList、Vector、LinkedList的区别(源码分析)

1、首先先看一下类集中Collection接口之下的实现子类继承关系

在这里插入图片描述

2、首先,他们的使用效果是一样的,没区别,如下所示:
  1. 使用ArrayList子类:在这里插入图片描述
  2. 使用Vector子类(用的少)在这里插入图片描述
  3. 使用LinkedList子类在这里插入图片描述
3、下面详细说明一下List接口下的三个子类ArrayList、Vector、LinkedList之间的区别:
3.1、ArrayList与Vector之间的区别
1.出现版本:

Vector jdk1.0就有了;ArrayList jdk1.2才有;如图:
Vector
ArrayList

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、公共点:

底层均使用数组实现

4、ArrayList与LinkedList之间的区别:
LinkedList底层采用双向链表实现,复杂度为1;
ArrayList底层采用数组实现,复杂度为n;
都采用异步实现,没有加锁;
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值