您的位置:

Java中Vector和List的区别

一、Vector和List的概述

在Java中,Vector和List都是用于存储一组元素的容器,它们都实现了List接口,因此拥有List特征:元素可重复,有序。但是,它们之间还存在一些差异。

import java.util.*;

public class Vector_vs_List {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Java");
        vector.add("Python");
        vector.add("C++");
        vector.add("C#");

        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");
        list.add("C#");

        System.out.println("Vector: " + vector);
        System.out.println("List: " + list);
    }
}

以上代码创建了一个Vector和一个List容器,并将一些元素添加到容器中,然后输出它们。运行结果:

Vector: [Java, Python, C++, C#]
List: [Java, Python, C++, C#]

Vector和List存储的数据是一样的,但是它们的内部实现机制有所不同,下面我们分别进行探究。

二、Vector和List的内部实现

1. Vector的内部实现

Vector是线程安全的,很早就出现在Java中,它的内部实现是采用数组来存储元素。

当Vector容量不足时,会进行扩容操作,即创建一个更大的数组,将原数组的内容复制到新数组中,增加容量。

默认情况下,Vector容量每次扩增为原来的2倍。即当Vector容量不足时,Vector会创建一个新的长度是原长度2倍的底层数组,将原数组元素复制到新数组,然后再将新增元素添加到数组中。如果Vector中的元素数量不断增加,就需要不断进行扩容操作,而且每次扩容都要复制数组,降低了性能。

以下是Vector扩容的代码示例:

private void grow(int minCapacity) {
    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);
}

其中,minCapacity指的是需要容器具备的最小容量,而capacityIncrement是Vector每次扩容的容量增量。

2. List的内部实现

List的实现类有很多,比如ArrayList、LinkedList等,其中ArrayList是最常用的。

ArrayList也是用数组来存储元素,但它的扩容机制不同于Vector。当ArrayList容量不足时,会创建一个新数组,并将原数组的内容复制到新数组中,同时利用System.arraycopy方法,实现数组的复制,以此来增加容量。

与Vector不同的是,ArrayList的默认扩容因子是1.5倍,而非2倍。

以下是ArrayList扩容的代码示例:

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

其中,">>"是位运算符中的右移运算符。如:4 >> 1的结果是2。

三、Vector和List的区别

1. 线程安全性

Vector是线程安全的,因此可以在并发环境中使用。但是,由于线程安全的需求越来越多地被提出,Java官方也在后来的版本中提供了其他数据结构,如ConcurrentHashMap等,替代了许多早期的容器功能。

List是非线程安全的,也就是说,当多个线程同时对一个List进行操作时,可能会破坏原来的数据结构。此时可以采用线程安全的List实现,如CopyOnWriteArrayList。

2. 性能

由于Vector在扩容时必须要复制其内部数组,因此在元素数量较大时,其性能会受到影响。

ArrayList的扩容机制虽然相对于Vector更为高效,但由于其底层还是采用数组实现,因此在插入或删除元素时,需要移动整个数组的元素,性能也是比LinkedList要低的。

LinkedList在进行插入和删除操作时,只需要调整前后元素的指针,因此实际上会更为高效。不过,它也有自己的缺点,就是它不支持随机访问,如果需要访问某个元素,只能从头节点开始不断遍历。

3. 使用场景

如果在操作较少的情况下,选择使用ArrayList可能会更高效,它支持快速随机访问,不需要像LinkedList那样进行遍历。但如果插入和删除操作较为频繁,那就选择LinkedList更为合适。

另外,如果需要在多线程环境中使用,可以选择使用ConcurrentHashMap等线程安全的容器。

四、总结

Vector和List都是用于存储元素的容器,它们的底层实现机制略有不同,Vector的扩容机制性能较低,而ArrayList虽然扩容机制较为高效,但其在插入和删除操作时也有性能问题。另外,在多线程环境下,需要使用线程安全的容器。

import java.util.*;

public class Vector_vs_List {
    public static void main(String[] args) {
        Vector<String> vector = new Vector<>();
        vector.add("Java");
        vector.add("Python");
        vector.add("C++");
        vector.add("C#");

        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("Python");
        list.add("C++");
        list.add("C#");

        System.out.println("Vector: " + vector);
        System.out.println("List: " + list);
    }
}