Vector源码解读以及与ArrayList的区别

1、概述

VectorArrayList类似,内部也是维护一个Object的数组 protected Object[] elementData,也允许null存在.其实现了 ListRandomAccess 、Cloneable 、java.io.Serializable.内部的方法和ArrayList一样的,只是加上 synchronized 关键字, 保证线程安全.

Vector源码解读以及与ArrayList的区别_第1张图片

需要深入了解它,便要从成员变量构造方法主要方法深入

2、成员变量

protected Object[] elementData; // Vector 内部维护的数组,用来存储数据
protected int elementCount;    //  存储元素个数
protected int capacityIncrement;  // 扩容时的增加量,大于0 增加capacityIncrement 否则就是扩为 2 倍
private static final long serialVersionUID = -2767605614048989439L;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

elementCount实际存储的元素个数, capacityIncrement是增加量,如果增加量大于0 就扩容为 capacityIncrement的值。

就比如可以指定增加量的值大小:capacityIncrement初始化为2,下次扩容时判断capacityIncrement是否大于0 ,大于零就会增加capacityIncrement的容量值(扩容).

List vector = new Vector<>(1,2);

其中还有一个属性也是比较重要的,不过不是它的,而是它的父类的属性。

protected transient int modCount = 0; 

 modCount 是ArrayList 继承自 AbstractList 的属性,它是用来记录集合的尺寸被修改次数的,addremove 方法会导致 modCount +1.

3、构造方法

初始化时提供了四个方法

public Vector()
public Vector(int initialCapacity)
public Vector(int initialCapacity, int capacityIncrement)
public Vector(Collection c) 

无参构造方法

/**
 * Constructs an empty vector so that its internal data array
 * has size {@code 10} and its standard capacity increment is
 * zero.
 */
public Vector() {
    this(10);
}

既然无参构造方法中使用有参构造方法 :public Vector(int initialCapacity).默认初始化增量为0

public Vector(int initialCapacity) {
    this(initialCapacity, 0);// 初始化增量为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;
}

初始化elementData数组的容量大小为initialCapacity,并且增量为capacityIncrement.

指定Collection的参数有参构造

public Vector(Collection c) {
  elementData = c.toArray();
  elementCount = elementData.length;
  // defend against c.toArray (incorrectly) not returning Object[]
  // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
  if (elementData.getClass() != Object[].class)
    elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

判断elementData的class类型是否是Object[]不是就做转换。(defend against c.toArray (incorrectly) not returning Object[]

4、Vector扩容机制分析(重点)

演示扩容机制的代码:

public class TestVector {
    public static void main(String[] args) {
        List vector = new Vector<>(1,2);
        for (int i = 0; i < 10; i++) {
            vector.add(i);
        }
        vector.add(1);
    }
}

主要通过deburg方式,查看代码执行的过程,当第11次在添加元素1时,查看源码分析过程:

public synchronized boolean add(E e) {
    modCount++;
    add(e, elementData, elementCount);
   return true;
}

该方法是一个线程安全的方法,在调用add(e, elementData, elementCount);源码如下:elementCount是当前的数组元素个数.

private void add(E e, Object[] elementData, int s) {
   if (s == elementData.length)
        elementData = grow();
   elementData[s] = e;
   elementCount = s + 1;
}

判断当前数组元素的个数是否等于最初始化的大小的容量,对elementData数组进行扩容grow()

//第一步:
private Object[] grow() {
   return grow(elementCount + 1); // 11
}
// 第二步:
private Object[] grow(int minCapacity) {
   return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
}

真正的扩容newCapacity()方法:

private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
    if (newCapacity - minCapacity <= 0) {
         if (minCapacity < 0) // overflow
              throw new OutOfMemoryError();
          return minCapacity;
     }
     return (newCapacity - MAX_ARRAY_SIZE <= 0)
            ? newCapacity
            : hugeCapacity(minCapacity);
}

private static int hugeCapacity(int minCapacity) {
     if (minCapacity < 0) // overflow
          throw new OutOfMemoryError();
     return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

首先获取当前数组的长度length,并且对增量判断(capacityIncrement > 0),无参构造是默认增量为0,因此就扩容为2倍.其中还对扩容后的newCapacity 长度是否超过最大值判断。没有超过就是返回newCapacity ,超过返回Integer.MAX_VALUE 最大值.

5、Vector源码结论(重点)

  • Vector底层也是一个对象数组 protected Object  [ ] elementData;
  • Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized ;安全但是效率就不高了。
  • 扩容倍数如果是无参构造,默认是创建一个10的对象数组,超过容量后就2倍扩容 (除非指定增量就按照增量大小进行扩容);指定大小创建对象时,就按照大小创建对象(指定容量的Vector对象

6、Vector和ArrayList的区别(重点)

  1. Vector是线程安全的,ArrayList不是线程安全的(主要区别
  2. ArrayList无参构造方法初始容量为0,Vector的无参构造方法初始为10
  3. ArrayList不可以设置扩容容量默认是1.5倍,Vector可以设置,默认是2倍

7、Vector和Collections.synchronizdList(重点)

Vector是java.util包的一个类,SynchronizedList是java.Collections中的一个静态内部类。

Collections.synchronizedList(List list)方法返回一个线程安全的List。

因此sychronizedList和Vector没有区别,为什么还要提供两种线程安全的List呢??接下来看看Collections.synchronizedList源码

static class SynchronizedCollection implements Collection, Serializable {
    private static final long serialVersionUID = 3053995032091335093L;

    final Collection c;  // Backing Collection
    final Object mutex;     // Object on which to synchronize
    SynchronizedCollection(Collection c) {
        this.c = Objects.requireNonNull(c);
        mutex = this;
    }

    SynchronizedCollection(Collection c, Object mutex) {
         this.c = Objects.requireNonNull(c);
         this.mutex = Objects.requireNonNull(mutex);
    }
    //....
}

通过Collections.synchronizedList(List list) 创建一个线程安全的list

List list1 = Collections.synchronizedList(list);

通过deburg方式查看到源码

public static  List synchronizedList(List list) {
     return (list instanceof RandomAccess ?
            new SynchronizedRandomAccessList<>(list) :
            new SynchronizedList<>(list));
}

查看其中方法源码:发现是加了synchronized同步代码块的。并不是所有的方法都是同步代码块的,有些是没有加的,需要手动加上锁,比如ListIterator

public boolean add(E e) {
    synchronized (mutex) {return c.add(e);}
}
public boolean remove(Object o) {
     synchronized (mutex) {return c.remove(o);}
}

两者区别

  • Vector使用同步方法,Collections.synchronizedList使用的是同步代码块 
  • Vector的扩容数组是2倍(无参构造时,默默是2倍)而synchronizedList是使用ArrayList的扩容机制
  • Collections.synchronizedList在遍历时需要手动加锁处理,Vector在遍历方法加了synchronized关键字

你可能感兴趣的:(Javase,java)