新手读源码__Vector,扩容不单单是2倍

前言

上一次分析集合的源码还是4.20,一晃半个月过去了,由于hashMap中遇到了红黑树,于是我决定去看下二叉排序树,AVL,B,B+,RB-Tree,这几种树,然后这10几天中因为《深入理解JVM》到了,也基本上都在看,看到了200页。后悔当时数据结构没好好学,AVL之流都没咋学。不过放下负担,好好去学才是正解,下面进入正题Vector

开篇疑问

在我看过的资料中,或者博文中,都会简单的说,ArrayList和Vector的区别在于ArrayList是1.5倍扩容Vector是2倍扩容,还有就是线程安全,今天看了源码的我,才发现,原来Vectory还可以支持定量增容

维护的属性

维护的属性很简单,主要有三个

protected Object[] elementData; //储存对象的数组
protected int elementCount;     // 对象的计数
protected int capacityIncrement;    // 指定的增量大小

构造方法

1、无参数构造,默认容量为10,不提供增量大小->0

    public Vector() {
        this(10);
    }

2、提供初始容量,不提供增量大小->0

    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

3、提供初始容量和增量大小,检测增量值要大于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;
    }

构造方法通过逐级调用,从而达到默认值的效果

add增加

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

我们可以看到,当容量满了的时候就会进行扩容操作grow,扩容是比较有意思的地方

扩容

    // 将旧容量+1,作为参数传递
    private Object[] grow() {
        return grow(elementCount + 1);
    }

    //数组复制,查看一下newCapacity( )
    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));
    }

    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);
    }

真正的扩容就是newCapacity()这个函数,首先它判断增量是否大于0,也就是判断是否有最初设定的增量大小,如果有增量大小,新容量=增量+旧容量,如果没有增量则容量变为原来的两倍,同时确保容量不超过最大容量MAX__ARRAY__SIZE

删除remove

    public boolean remove(Object o) {
        return removeElement(o);
    }

    public synchronized boolean removeElement(Object obj) {
        modCount++;
        int i = indexOf(obj);
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }

    // 找到对象的索引
    public synchronized int indexOf(Object o, int index) {
        if (o == null) {
            for (int i = index ; i < elementCount ; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index ; i < elementCount ; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    // 移除并复制原来的数组
    public synchronized void removeElementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        int j = elementCount - index - 1;
        if (j > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        modCount++;
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work */
    }

需要看一下这个复制的API

void java.lang.System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

它的意思是,从原数组的某一个位置开始复制到新数组的某一个元素,总长度是length,它是由Hotspot虚拟机来实现的。同样ArrayList中,也是用这种方法是实现的,叫fastRemove()

遍历

package test;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

public class Test 
{
    public static void main(String[] args)
    {
        Vector<String> vector = new Vector();
        vector.add("1");
        vector.add("2");
        vector.add("3");
        // index访问
        for (int i = 0; i < vector.size(); i++) {
            System.out.println(vector.get(i));
        }

        // for循环
        for (String string : vector) {
            System.out.println(string);
        }

        //迭代器
        Iterator<String> it = vector.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }

        // Enumeration
        Enumeration<String> enumeration = vector.elements();
        while (enumeration.hasMoreElements()) {
            System.out.println(enumeration.nextElement());
        }
    }
}

之前我只知道iterator迭代器,今天才发现原来还有枚举,查看这个接口的定义

Enumeration

public interface Enumeration<E> {
    boolean hasMoreElements();
    E nextElement();
    default Iterator<E> asIterator() {
        return new Iterator<>() {
            @Override public boolean hasNext() {
                return hasMoreElements();
            }
            @Override public E next() {
                return nextElement();
            }
        };
    }

这个接口主要是访问,并不提供删除操作,但是也可以通过它来返回一个iterator迭代器,也就是asIterator方法

总结

总的来说,它的重点在于扩容提供的增量扩容,可以提供固定的增长量,然后还有一个就是认识了下Enumberation这个接口,它的内部实现还是不难的,所以到这里就算是了解了

猜你喜欢

转载自blog.csdn.net/qq_41376740/article/details/80228809