Java中ArrayList的底层扩容机制和Vector的底层扩容机制,以及ArrayList和Vector的对比与选择。附源码

在 Java 的 ArrayList 中,当数组的容量不足以存储新元素时,会触发扩容操作。ArrayList 的底层使用数组来存储元素,而扩容机制主要涉及到创建一个更大的数组,并将现有元素复制到新数组中。ArrayList 支持无参扩容和有参扩容两种机制。

无参扩容机制
无参扩容是指首次的扩容大小是10,后面在元素数量达到容量上限时,ArrayList 会创建一个新的数组,其大小通常是原数组容量的1.5倍,并将原数组中的元素复制到新数组中。这个过程涉及到创建新数组、复制元素等步骤(copyOf方法)。

以下是无参扩容的源码示例:

//第一步
public boolean add (E e){
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}
//第二步
private void ensureCapacityInternal ( int minCapacity){         																								ensureExplicitCapacity(calculateCapacity(elementData, 	minCapacity));
}
//第三步
private static int calculateCapacity (Object[]elementData,int minCapacity){
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		return Math.max(DEFAULT_CAPACITY, minCapacity);
	}//DEFAULT_CAPACITY为10
		return minCapacity;
}
//第四步
private void ensureExplicitCapacity ( int minCapacity){
	modCount++;

	// 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 + (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);
}

有参扩容机制
有参扩容是指允许开发者在添加元素时指定扩容的大小。通过传递一个整数作为参数,ArrayList 会根据指定的扩容大小进行数组的扩容。后面在元素数量达到容量上限时,ArrayList 会创建一个新的数组,其大小通常是原数组容量的1.5倍

有参扩容的源码示例:

//第一步
public ArrayList(int initialCapacity) {
	if (initialCapacity > 0) {
		this.elementData = new Object[initialCapacity];
	} else if (initialCapacity == 0) {
		this.elementData = EMPTY_ELEMENTDATA;
	} else {
		throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);                                             
    }
}
//第二步
private void ensureCapacityInternal ( int minCapacity){         																								ensureExplicitCapacity(calculateCapacity(elementData, 	minCapacity));
}
//第三步
private static int calculateCapacity (Object[]elementData,int minCapacity){
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		return Math.max(DEFAULT_CAPACITY, minCapacity);
	}//DEFAULT_CAPACITY为10
		return minCapacity;
}
//第四步
private void ensureExplicitCapacity ( int minCapacity){
	modCount++;

	// 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 + (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);
}

java.util.Vector 是 Java 中的一种动态数组实现,与 ArrayList 类似,它也支持无参扩容和有参扩容机制。Vector 是线程安全的,但在多线程环境下性能较差,已经不太推荐使用。

无参扩容机制
无参扩容是指首次的扩容大小默认是10,后面在元素数量达到容量上限时,Vector 会创建一个新的数组,其大小通常是原数组容量的2倍,并将原数组中的元素复制到新数组中。这个过程涉及到创建新数组、复制元素等步骤(copyOf方法)。

以下是无参扩容的源码示例:

//第一步
    public Vector() {
        this(10);
    }
//第二步
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }
//第三步
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
//第四步
    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);
    }

有参扩容机制
有参扩容是指允许开发者在添加元素时指定扩容的大小。通过传递一个整数作为参数,Vector 会根据指定的扩容大小进行数组的扩容。后面在元素数量达到容量上限时,Vector 会创建一个新的数组,其大小通常是原数组容量的2倍

有参扩容的源码示例:

//第一步
    public Vector(int initialCapacity) {
        this(initialCapacity, 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;
    }
//第三步
    protected AbstractList() {
    }
//第四步
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }
//第五步
    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);
    }

小结:
ArrayListVector 都是 Java 集合框架中动态数组的实现,它们在很多方面非常相似,但也有一些关键的区别。在选择使用哪个类时,需要考虑到它们的性能、线程安全性和适用场景等因素。

ArrayList 和 Vector 的对比:

  1. 线程安全性

    • ArrayList:不是线程安全的,多个线程同时访问和修改 ArrayList 可能会导致并发问题。
    • Vector:是线程安全的,内部使用同步机制来确保多线程下的安全访问。
  2. 性能

    • ArrayList:由于不需要进行额外的同步操作,相对于 Vector 在单线程环境下性能更好。
    • Vector:由于需要进行同步操作,性能相对较差。在多线程环境下,由于同步开销,可能也比 ArrayList 性能较差。
  3. 扩容机制

    • ArrayListVector 的扩容机制类似,但 ArrayList 可以通过构造函数 ArrayList(int initialCapacity)ensureCapacity(int minCapacity) 方法来设置初始容量,而 Vector 只能通过构造函数来设置初始容量。
  4. 适用场景

    • 如果在单线程环境下使用,且不需要线程安全性,推荐使用 ArrayList
    • 如果在多线程环境下使用,或者需要考虑线程安全性,可以考虑使用 Vector。但请注意,现代 Java 中更倾向于使用并发集合(如 ConcurrentHashMapCopyOnWriteArrayList 等)来实现更高效的线程安全。

如何选择:

  1. 性能要求:如果性能是首要考虑因素,且在单线程环境下使用,选择 ArrayList。如果线程安全性更重要,可以考虑使用其他线程安全的集合,而不是 Vector

  2. 线程安全性:如果需要在线程之间共享数据,或者在多线程环境下使用,而且没有更好的线程安全替代品,可以考虑使用 Vector。但要知道 Vector 的性能会受到影响。

  3. 现代替代品:在现代 Java 中,还有更适合多线程环境的集合实现,如 CopyOnWriteArrayList 或并发集合框架。这些集合能够提供更好的性能和线程安全性。

综上所述,除非有特定的需求,现代 Java 中更倾向于使用其他集合实现,而不是直接使用 Vector。在选择时,需要根据具体的需求和环境来权衡性能和线程安全性。

你可能感兴趣的:(java,算法,开发语言)