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