Vector源码分析

释放双眼,带上耳机,听听看~!

文章目录

  • ArrayList和Vector对比:
  • 底层数据结构
  • 构造方法
  • 扩容机制
  • 添加元素
  • 删除元素
  • 查询
  • 迭代器

本来今天是想看一下Stack的源码的,但是在看到Stack的父类结构时


1
2
3
1public class Stack<E> extends Vector<E>
2
3

我想到了我之前还没怎么看过Vector的源码,甚至乎还很少用,我之前对他的了解大概就是停留在跟ArrayList很相似,是线程安全的ArrayList,先总结下ArrayList和Vector的不同之处,然后带着结论去看源码,找原因
ArrayList源码分析

ArrayList和Vector对比:

  • 相同之处:

  • 都是基于数组

    • 都支持随机访问
    • 默认容量都是10
    • 都支持动态扩容
    • 都支持fail—fast机制
  • 不同之处:

  • Vector历史比ArrayList久远,Vector是jdk1.0,ArrayList是jdk1.2

    • Vector是线程安全的,ArrayList线程不安全
    • Vector动态扩容默认扩容两倍,ArrayList是1.5倍

底层数据结构

Vector底层是基于数组实现的


1
2
3
1protected Object[] elementData;
2
3

ArrayList底层数据结构也是数组


1
2
3
1private static final Object[]
2
3

其他相关属性


1
2
3
4
5
6
1    //数组中元素数量
2    protected int elementCount;
3    //增长量
4    protected int capacityIncrement;
5
6

构造方法

无参构造,数组容量默认是10


1
2
3
4
5
6
1    //无参构造,数组容量默认是10
2    public Vector() {
3        this(10);
4    }
5
6

ArrayList默认数组容量也是10


1
2
3
4
5
6
7
8
9
1    //默认容量
2    private static final int DEFAULT_CAPACITY = 10;
3
4    //构造指定容量的数组(10)
5    public ArrayList() {
6        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
7    }
8
9

Vcetor其他构造方法:

指定容量和增长量构造


1
2
3
4
5
6
7
8
9
10
11
12
13
1    //创建指定容量大小的数组,设置增长量。
2    public Vector(int initialCapacity, int capacityIncrement) {
3        super();
4        if (initialCapacity < 0)
5            throw new IllegalArgumentException("Illegal Capacity: "+
6                                               initialCapacity);
7        //构造指定容量的数组
8        this.elementData = new Object[initialCapacity];
9        //设置增长量
10        this.capacityIncrement = capacityIncrement;
11    }
12
13

指定容量和增长量为0的构造:


1
2
3
4
5
1    public Vector(int initialCapacity) {
2        this(initialCapacity, 0);
3    }
4
5

传入指定集合构造


1
2
3
4
5
6
7
8
9
10
11
1    public Vector(Collection<? extends E> c) {
2        //转成数组,赋值
3        elementData = c.toArray();
4        elementCount = elementData.length;
5        // c.toArray might (incorrectly) not return Object[] (see 6260652)
6        //如果不是Object[],要重建数组
7        if (elementData.getClass() != Object[].class)
8            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
9    }
10
11

扩容机制

在了解添加元素之前我们需要理清Vector的扩容机制是怎样的,其实跟ArrayList的扩容机制也很相似

1.计算最小容量:

最小容量 = 当前数组元素数量 + 1,此举的目的就是判断是否需要扩容,最小容量就是相当于成功添加了一个元素后的新的数组元素数量,如果这个新的数组元素数量大于数组长度,那么肯定需要扩容


1
2
3
4
5
6
7
1    private void ensureCapacityHelper(int minCapacity) {
2        // overflow-conscious code
3        if (minCapacity - elementData.length > 0)
4            grow(minCapacity);
5    }
6
7

2.传入最小容量开始扩容:

  • 如果当前数组的增长量 > 0则新数组容量 = 旧数组容量 + 增长量

  • 否则,则新数组容量 = 2 * 旧数组容量

  • 求出新数组容量后,如果新数组容量 < 最小容量,那么新数组容量 = 最小容量

  • 如果新数组容量 > 最大数组容量,则新数组容量 = 整数最大值


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1    //最小数组容量
2    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
3
4    //扩容
5    private void grow(int minCapacity) {
6        //旧的数组容量
7        int oldCapacity = elementData.length;
8        //新数组容量
9        //如果当前数组的增长量 &gt; 0则新数组容量 = 旧数组容量 + 增长量
10        //否则,则新数组容量 = 2 * 旧数组容量
11        int newCapacity = oldCapacity + ((capacityIncrement &gt; 0) ?
12                                         capacityIncrement : oldCapacity);
13        //求出新数组容量后,如果新数组容量 &lt; 最小容量,那么新数组容量 = 最小容量                                  
14        if (newCapacity - minCapacity &lt; 0)
15            newCapacity = minCapacity;
16        //如果新数组容量 &gt; 最大数组容量,则新数组容量 = 整数最大值
17        if (newCapacity - MAX_ARRAY_SIZE &gt; 0)
18            newCapacity = hugeCapacity(minCapacity);
19        //真正扩容,实际上就是数组的复制和移动    
20        elementData = Arrays.copyOf(elementData, newCapacity);
21    }
22
23    //判断是取最大数组容量还是整数最大值
24    private static int hugeCapacity(int minCapacity) {
25        if (minCapacity &lt; 0) // overflow
26            throw new OutOfMemoryError();
27        return (minCapacity &gt; MAX_ARRAY_SIZE) ?
28            Integer.MAX_VALUE :
29            MAX_ARRAY_SIZE;
30    }
31
32

4.扩容实际:数组复制和移动


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1    public static &lt;T,U&gt; T[] copyOf(U[] original, int newLength, Class&lt;? extends T[]&gt; newType) {
2        @SuppressWarnings(&quot;unchecked&quot;)
3        T[] copy = ((Object)newType == (Object)Object[].class)
4            ? (T[]) new Object[newLength]
5            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
6        //params0:original:原数组
7        //param1:srcPos:原数组开始位置
8        //param2:copy:新数组
9        //param3:destPost:新数组开始位置
10        //param4:copyLength:要copy的数组的长度    
11        System.arraycopy(original, 0, copy, 0,
12                         Math.min(original.length, newLength));
13        return copy;
14    }
15
16

ArrayList的扩容机制其实和Vector很相似,至少原理是一致的,但是在扩容大小上不一样

因为ArrayList没有增长量这一概念,所以ArrayList默认扩容1.5倍


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1    private void grow(int minCapacity) {
2        // 原来的数组容量 = 数组长度
3        int oldCapacity = elementData.length;
4        // 新的数组容量 = 原数组容量+原数组容量/2
5        int newCapacity = oldCapacity + (oldCapacity &gt;&gt; 1);
6        //判断下传进来的最小容量 (最小容量 = 当前数组元素数目 + 1)
7        // 如果比当前新数组容量小,则使用最容量
8        if (newCapacity - minCapacity &lt; 0)
9            newCapacity = minCapacity;
10        //如果判断当前新容量是否超过最大的数组容量 MAX_ARRAY_SIZE =  Integer.MAX_VALUE - 8
11        if (newCapacity - MAX_ARRAY_SIZE &gt; 0)
12            newCapacity = hugeCapacity(minCapacity);
13        //开始扩容
14        elementData = Arrays.copyOf(elementData, newCapacity);
15    }
16    
17    //如果判断当前新容量是否超过最大的数组容量 MAX_ARRAY_SIZE =  Integer.MAX_VALUE - 8
18    private static int hugeCapacity(int minCapacity) {
19        if (minCapacity &lt; 0) // overflow
20            throw new OutOfMemoryError();
21        //如果超多最大数组容量则使用Integer的最大数值,否则还是使用最大数组容量
22        return (minCapacity &gt; MAX_ARRAY_SIZE) ?
23            Integer.MAX_VALUE :
24            MAX_ARRAY_SIZE;
25    }
26
27

ArrayList扩容流程:

Vector源码分析

添加元素

数组尾部添加指定元素

可以看到添加方法上带有synchronized同步关键字,保证了在添加元素时的线程安全,但是也会带来获取锁和释放锁的效率问题


1
2
3
4
5
6
7
8
9
1    public synchronized void addElement(E obj) {
2        modCount++;
3        //判断是否需要扩容
4        ensureCapacityHelper(elementCount + 1);
5        //直接根据下标添加
6        elementData[elementCount++] = obj;
7    }
8
9

指定位置添加指定元素


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1    public synchronized void insertElementAt(E obj, int index) {
2        modCount++;
3        if (index &gt; elementCount) {
4            throw new ArrayIndexOutOfBoundsException(index
5                                                     + &quot; &gt; &quot; + elementCount);
6        }
7        //判断是否需要扩容
8        ensureCapacityHelper(elementCount + 1);
9        //数组移动和复制,腾出index位置 index后的元素向后移动一位
10        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
11        //下标添加
12        elementData[index] = obj;
13        //元素数量+1
14        elementCount++;
15    }
16
17

添加指定集合


1
2
3
4
5
6
7
8
9
10
11
12
1    public synchronized boolean addAll(Collection&lt;? extends E&gt; c) {
2        modCount++;
3        Object[] a = c.toArray();
4        int numNew = a.length;
5        ensureCapacityHelper(elementCount + numNew);
6         //扩容,复制到数组后面
7        System.arraycopy(a, 0, elementData, elementCount, numNew);
8        elementCount += numNew;
9        return numNew != 0;
10    }
11
12

删除元素

删除指定下标元素


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
1    public synchronized E remove(int index) {
2        modCount++;
3        if (index &gt;= elementCount)
4            throw new ArrayIndexOutOfBoundsException(index);
5        //原来该下标对应的元素值    
6        E oldValue = elementData(index);
7        //index后面元素的数量
8        int numMoved = elementCount - index - 1;
9        //如果该元素不是最后一个元素
10        if (numMoved &gt; 0)
11            //该元素后面的元素向前移动一位,覆盖删除
12            System.arraycopy(elementData, index+1, elementData, index,
13                             numMoved);
14        //数组最后多余的一位为null,gc                    
15        elementData[--elementCount] = null; // Let gc do its work
16
17        return oldValue;
18    }
19
20    //和上边方法其实思路是一样的
21    public synchronized void removeElementAt(int index) {
22        modCount++;
23        //检查
24        if (index &gt;= elementCount) {
25            throw new ArrayIndexOutOfBoundsException(index + &quot; &gt;= &quot; +
26                                                     elementCount);
27        }
28        else if (index &lt; 0) {
29            throw new ArrayIndexOutOfBoundsException(index);
30        }
31        int j = elementCount - index - 1;
32        if (j &gt; 0) {
33             //该元素后面的元素向前移动一位,覆盖删除
34            System.arraycopy(elementData, index + 1, elementData, index, j);
35        }
36        //数组最后多余的一位为null,gc    
37        elementCount--;
38        elementData[elementCount] = null; /* to let gc do its work */
39    }
40
41

删除指定元素


1
2
3
4
5
6
7
8
9
10
11
12
13
1    public synchronized boolean removeElement(Object obj) {
2        modCount++;
3        //找到该元素下标
4        int i = indexOf(obj);
5        if (i &gt;= 0) {
6            //下标正确则根据下标删除
7            removeElementAt(i);
8            return true;
9        }
10        return false;
11    }
12
13

删除所有元素


1
2
3
4
5
6
7
8
9
10
1    public synchronized void removeAllElements() {
2        modCount++;
3        //循环删除每一个元素,gc
4        for (int i = 0; i &lt; elementCount; i++)
5            elementData[i] = null;
6
7        elementCount = 0;
8    }
9
10

删除指定范围的元素


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1    protected synchronized void removeRange(int fromIndex, int toIndex) {
2        modCount++;
3        //原理还是数组的移动,将toIndex后的元素向前移动 toIndex - fromIndex
4        int numMoved = elementCount - toIndex;
5        System.arraycopy(elementData, toIndex, elementData, fromIndex,
6                         numMoved);
7
8        // Let gc do its work
9        int newElementCount = elementCount - (toIndex-fromIndex);
10        while (elementCount != newElementCount)
11            elementData[--elementCount] = null;
12    }
13
14

查询

从指定下标开始找到指定元素第一次出现的下标

从前往后找


1
2
3
4
5
6
7
8
9
10
11
12
13
14
1    public synchronized int indexOf(Object o, int index) {
2        if (o == null) {
3            for (int i = index ; i &lt; elementCount ; i++)
4                if (elementData[i]==null)
5                    return i;
6        } else {
7            for (int i = index ; i &lt; elementCount ; i++)
8                if (o.equals(elementData[i]))
9                    return i;
10        }
11        return -1;
12    }
13
14

从后往前找


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1    public synchronized int lastIndexOf(Object o, int index) {
2        if (index &gt;= elementCount)
3            throw new IndexOutOfBoundsException(index + &quot; &gt;= &quot;+ elementCount);
4
5        if (o == null) {
6            for (int i = index; i &gt;= 0; i--)
7                if (elementData[i]==null)
8                    return i;
9        } else {
10            for (int i = index; i &gt;= 0; i--)
11                if (o.equals(elementData[i]))
12                    return i;
13        }
14        return -1;
15    }
16
17

返回指定下标的元素


1
2
3
4
5
6
7
8
9
10
11
12
1    E elementData(int index) {
2        return (E) elementData[index];
3    }
4
5    public synchronized E get(int index) {
6        if (index &gt;= elementCount)
7            throw new ArrayIndexOutOfBoundsException(index);
8
9        return elementData(index);
10    }
11
12

是否包含指定元素


1
2
3
4
5
6
1    //看没有该下标
2    public boolean contains(Object o) {
3        return indexOf(o, 0) &gt;= 0;
4    }
5
6

迭代器

迭代器和ArrayList相比是差不多的,包括实现也是,可以参考ArrayList源码分析

给TA打赏
共{{data.count}}人
人已打赏
安全经验

如何避免Adsense违规封号

2021-10-11 16:36:11

安全经验

安全咨询服务

2022-1-12 14:11:49

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索