1. vector 是什么?
vector是 java 早期版本(从 jdk 1.0 开始)就存在的一个动态数组实现。它位于 java.util包中,是 java 集合框架(java collections framework, jcf)的一部分。
本质:一个可以根据需要自动增长和缩小的对象数组。
特点:
- 有序(ordered):元素按照插入的顺序存放,可以通过整数索引(从 0 开始)精确地访问每个元素。
- 可重复:允许包含重复的元素。
- 线程安全(synchronized):这是
vector最显著的特点之一。其绝大多数公共方法(如add,get,remove)都使用了synchronized关键字修饰,保证了在多线程环境下,同一时间只有一个线程能对 vector 实例进行修改或读取,从而避免了数据的不一致性。
2. 核心特性详解
a) 动态扩容
这是 vector和原始数组最根本的区别。你无需在创建时指定最终的大小,它会自动管理容量。
- 初始容量(initial capacity):创建
vector时内部的数组大小。默认是 10。 - 扩容增量(capacity increment):可以指定一个增量值。当需要扩容时,新的容量将是
旧容量 + 增量值。如果创建时未指定增量(或指定为 0),则默认策略是扩容为原来的 2 倍(newcapacity = oldcapacity * 2)。 - 扩容时机:当尝试添加一个新元素(例如
add(e))并且当前元素数量已经等于内部数组的长度时,就会触发扩容操作。
示例:
vector<string> vector = new vector<>(); // 初始容量=10, 增量=0(默认2倍扩容)
for (int i = 0; i < 11; i++) {
vector.add("element " + i); // 添加第11个元素时,容量从10扩到20
}b) 线程安全
正如之前提到的,vector的方法大多是同步的。这意味着它在多线程环境下是安全的,你可以多个线程同时操作一个 vector而不会破坏其内部状态(如不会造成数据覆盖)。
示例代码片段(查看源码):
// vector 的 add 方法源码大致长这样:
public synchronized boolean add(e e) {
modcount++;
ensurecapacityhelper(elementcount + 1); // 检查并扩容
elementdata[elementcount++] = e;
return true;
}
// get 方法也是同步的
public synchronized e get(int index) {
if (index >= elementcount)
throw new arrayindexoutofboundsexception(index);
return elementdata(index);
}3. 优缺点分析
优点:
- 线程安全:最大的优点,在不需要额外代码的情况下,即可用于多线程场景。
- 使用简单:作为动态数组,其 api 直观易用,避免了原始数组的固定大小限制。
缺点:
- 性能开销:这是最关键的缺点。同步(
synchronized)带来了巨大的性能代价。每次方法调用都需要获取和释放锁,这在单线程环境下是完全不必要的开销,会导致程序变慢。 - 过时的设计:在 java 1.2 引入更现代的集合框架(如
arraylist,hashmap)之后,vector虽然被保留了,但通常被认为是一种“遗留类”(legacy class)。它的方法名(如addelement,elementat)也没有遵循新的集合接口约定(如add,get),尽管为了兼容它也实现了这些新方法。 - 不如现代的并发集合:即使在需要线程安全的场景下,java 5 引入的
java.util.concurrent包中的集合类(如copyonwritearraylist,concurrenthashmap)通常提供了更优的性能和更精细的锁策略(如读写锁、写时复制)。
4. vector vs arraylist
这是最常被问到的问题。arraylist是 vector的非同步现代替代品。
特性 | vector | arraylist |
|---|---|---|
线程安全 | 是 (同步方法) | 否 |
性能 | 较低 (因同步开销) | 较高 (无同步开销) |
扩容策略 | 默认2倍,可指定增量 | 默认1.5倍 ( |
历史 | jdk 1.0,遗留类 | jdk 1.2,现代集合框架主力 |
迭代器 |
|
|
推荐使用 | 极少,仅在遗留系统或非常简单的多线程场景 | 绝大多数单线程场景的首选 |
5. 如何使用 vector?
尽管不推荐在新项目中使用,但了解其 api 仍有必要。
创建 vector:
// 1. 默认构造:容量10,扩容时容量翻倍
vector<string> vec1 = new vector<>();
// 2. 指定初始容量
vector<string> vec2 = new vector<>(100);
// 3. 指定初始容量和扩容增量
vector<string> vec3 = new vector<>(100, 10); // 每次扩容增加10
// 4. 通过其他集合创建
list<string> list = arrays.aslist("a", "b", "c");
vector<string> vec4 = new vector<>(list);基本操作:
vector<integer> vector = new vector<>();
// 添加元素
vector.add(10);
vector.add(20);
vector.add(1, 15); // 在索引1处插入
// 获取元素
int element = vector.get(0); // 10
// 修改元素
vector.set(0, 100); // 将索引0改为100
// 删除元素
vector.remove(0); // 删除索引0的元素
vector.remove(integer.valueof(20)); // 删除值为20的元素
// 大小和容量
int size = vector.size(); // 元素数量
int capacity = vector.capacity(); // 当前底层数组的容量
// 遍历 (推荐方式)
for (integer num : vector) {
system.out.println(num);
}
// 枚举器 (古老的方式,不推荐)
enumeration<integer> enumeration = vector.elements();
while (enumeration.hasmoreelements()) {
system.out.println(enumeration.nextelement());
}6. 现代开发中的替代方案和建议
单线程环境:
- 绝对首选 arraylist。它没有同步开销,性能远超
vector。
多线程环境:
- 需要同步的 list:可以使用
collections.synchronizedlist(new arraylist())来包装一个arraylist,这样得到的 list 是同步的。这比直接使用vector更灵活,因为你可以在需要同步时再包装,不需要时就用原始的arraylist。 - 高并发读,少写:考虑使用
copyonwritearraylist。它在写操作时复制整个新数组,读操作无需加锁,性能极高。 - 需要更复杂的并发操作:使用
java.util.concurrent包下的其他并发集合类。
示例:使用 collections.synchronizedlist
list<string> syncedlist = collections.synchronizedlist(new arraylist<>());
// 在迭代时,你必须手动同步!
synchronized(syncedlist) {
iterator<string> i = syncedlist.iterator();
while (i.hasnext()) {
system.out.println(i.next());
}
}总结
vector是一个线程安全的、动态扩容的数组实现。- 它的同步特性导致性能较差,是其在现代开发中不被推荐的主要原因。
- 在单线程环境中,总是优先使用
arraylist。 - 在多线程环境中,优先考虑
collections.synchronizedlist()、copyonwritearraylist或其他java.util.concurrent包下的并发容器,而不是vector。
理解 vector更多的是为了理解 java 集合框架的历史和线程安全的概念,而不是为了在新代码中使用它。
到此这篇关于java中vector的详细说明的文章就介绍到这了,更多相关java vector内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论