java collection_Java基础学习之Collection—List线程安全篇(Vector)

8e4537ba7019aa08daae26356fc91608.png

前言

老规矩,先把官方注释完整的放出来。

/**
 * The {@code Vector} class implements a growable array of
 * objects. Like an array, it contains components that can be
 * accessed using an integer index. However, the size of a
 * {@code Vector} can grow or shrink as needed to accommodate
 * adding and removing items after the {@code Vector} has been created.
 *
 * <p>Each vector tries to optimize storage management by maintaining a
 * {@code capacity} and a {@code capacityIncrement}. The
 * {@code capacity} is always at least as large as the vector
 * size; it is usually larger because as components are added to the
 * vector, the vector's storage increases in chunks the size of
 * {@code capacityIncrement}. An application can increase the
 * capacity of a vector before inserting a large number of
 * components; this reduces the amount of incremental reallocation.
 *
 * <p><a name="fail-fast">
 * The iterators returned by this class's {@link #iterator() iterator} and
 * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em></a>:
 * if the vector is structurally modified at any time after the iterator is
 * created, in any way except through the iterator's own
 * {@link ListIterator#remove() remove} or
 * {@link ListIterator#add(Object) add} methods, the iterator will throw a
 * {@link ConcurrentModificationException}.  Thus, in the face of
 * concurrent modification, the iterator fails quickly and cleanly, rather
 * than risking arbitrary, non-deterministic behavior at an undetermined
 * time in the future.  The {@link Enumeration Enumerations} returned by
 * the {@link #elements() elements} method are <em>not</em> fail-fast.
 *
 * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
 * throw {@code ConcurrentModificationException} on a best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators
 * should be used only to detect bugs.</i>
 *
 * <p>As of the Java 2 platform v1.2, this class was retrofitted to
 * implement the {@link List} interface, making it a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.  Unlike the new collection
 * implementations, {@code Vector} is synchronized.  If a thread-safe
 * implementation is not needed, it is recommended to use {@link
 * ArrayList} in place of {@code Vector}.

其实这里面的注释内容有关于快速失败和迭代器的部分跟LinkedList和ArrayList是一模一样的,我挑选一些Vector的特性把重点翻译一下。

Vector类实现了一个 可增长(growable)的数组对象,类似数组,它包含可以使用整数索引访问的组件。但是,在Vector创建之后,它的大小可以根据需要增长或缩小,以适应添加和删除等操作。
每个Vector都会试着通过维持 capacity(容量)capacityIncrement(扩容因子)来优化存储管理。
capacity(容量)总是至少和Vector的大小一样大,而它通常会更大一些,因为当成员被添加到Vector中时,Vector的存储量会成 块(chunks)增加,即capacityIncrement(扩容因子)的大小。
应用程序可以在插入大量成员之前增加Vector的容量;这减少了增量重新分配的代价。

源码

  1. 继承和实现
public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

Vector继承AbstractList抽象父类,实现了List接口(规定了List的操作规范)、RandomAccess(可随机访问)、Cloneable(可拷贝)、Serializable(可序列化)

(这话在ArrayList里面说过)

2. 变量

/**
     * The array buffer into which the components of the vector are
     * stored. The capacity of the vector is the length of this array buffer,
     * and is at least large enough to contain all the vector's elements.
     *
     * <p>Any array elements following the last element in the Vector are null.
     *
     * @serial
     */
    protected Object[] elementData;

    /**
     * The number of valid components in this {@code Vector} object.
     * Components {@code elementData[0]} through
     * {@code elementData[elementCount-1]} are the actual items.
     *
     * @serial
     */
    protected int elementCount;

    /**
     * The amount by which the capacity of the vector is automatically
     * incremented when its size becomes greater than its capacity.  If
     * the capacity increment is less than or equal to zero, the capacity
     * of the vector is doubled each time it needs to grow.
     *
     * @serial
     */
    protected int capacityIncrement;

Object[] elementData,这个就是Vector的本来面目了,朴实无华。

3.构造方法

public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
 public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
 public Vector() {
        this(10);
    }
public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }

两个参数分别是初始容量和扩容因子,初始容量默认是10,扩容因子默认为0。

入参为collection时,将其转化为数组。

4.扩容方法

对于ArrayList和vector这种对象数组来说,扩容操作都是开辟一块新的位置,然后将原先的数据复制过来。只不过vector多了一个“扩容因子”概念的存在。

private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        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;
    }
在Vector执行插入操作时,调用ensureCapacityHelper,传入的minCapacity为“elementCount + 1”,意味着默认扩容就是当前的大小加一。
然后判断如果扩容因子如果大于0,那么新的容量newCapacity的大小就是旧的容量oldCapacity加上扩容因子,否则新的容量就是oldCapacity×2.
然后当新的容量大于数组所能容纳的最大容量时,调用 hugeCapacity方法来计算,逻辑就是这个三目运算符
(minCapacity > MAX_ARRAY_SIZE)? Integer.MAX_VALUE : MAX_ARRAY_SIZE
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
Integer.MAX_VALUE = 2147483647;

和ArrayList一样,hugeCapacity为啥子会需要判断minCapacity <0呢?

假如列表中已经有
-1个元素,在添加新元素的时候,minCapacity 为原来的长度 + 1,溢出变为 minCapacity = -
-1,新的长度扩大到 1.5 倍也溢出为负数(绝对值 < minCapacity),此时
grow 方法中 新的长度 - 旧的长度 > 0(绝对值小的负数 - 绝对值大的负数),最后调用该方法时传递的 minCapacity 就是-
-1,将抛出异常。

最后如果 minCapacity 大于 ArrayList 能容纳的最大长度,就返回整型最大值,否则返回 MAX_ARRAY_SIZE
(这话在ArrayList介绍的时候也说过)哈哈哈哈我就复制粘贴一下

至于为什么加一会变负数,那就又牵扯到二进制存储的事儿了。大家可以搜索一下java中的Byte 127 加一等于多少?

5.线程同步

这里面总重要问题就是,Vector是以什么方式来保证线程安全呢??

synchronized

就这一个秘诀。

在面试的时候Vector和ArrayList经常被拿来提问,除了线程安全的区别之外,也可以说一说扩容因子对于容量扩容时候的影响。

今天的文章到这里结束,我们下一章节介绍CopyOnWriteArrayList<E>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值