Vector API定义了4种不同的构造函数:
Vector()
Vector(Collection<? extends E> c)
Vector(int initialCapacity)
Vector(int initialCapacity, int capacityIncrement)
但它们如何运作以及它们用于什么?我为什么要为矢量定义固定容量?即使我将初始容量设置为100,我也可以向向量添加101.项:
Vector<Object> test = new Vector<Object>(100);
for (int i = 0; i < 100; i++) {
test.add(new Object());
}
test.add(new Object());
System.out.println(test.size());
System.out.println(test.capacity());
在上面的代码中,第二个sysout(test.capacity())写入200.为什么此向量中的容量为200?初始容量为100,我没有定义容量增量。
我真的很想知道是否有使用这些建筑师的现实世界的例子?
一个熟悉的问题: 究竟是Vector.get(int position)和Vector.elementAt(int position)之间的区别?我读到在将Vector添加到Collection类之前定义了get方法,因此有必要在以后添加方法elementAt(int position)。真的吗?或者还有其他差异吗?
答案 0 :(得分:21)
初始容量就是:Vector
在施工时的容量。
Vector
是一个可动态增长的数据结构,它会根据需要重新分配其后备阵列。因此,没有最终容量,但您可以设置其初始值。
以下摘自Vector
API:
每个向量都会尝试通过维护
capacity
和capacityIncrement
来优化存储管理。capacity
始终至少与向量size
一样大;它通常更大,因为随着组件被添加到向量中,向量的存储以capacityIncrement
的大小增加。应用程序可以在插入大量组件之前增加向量的capacity
;这减少了增量重新分配的数量。
注意构建后,您也可以使用ensureCapacity
来达到同样的效果。
例如,假设您有100个要插入Vector
的元素。 nullary constructor将Vector
设置为初始容量为10,并且在增长时大小翻倍。这意味着要容纳100个元素,它可以加倍到20,40,80,最后是160,然后才能适应所有100个元素。
请注意,执行了4个增量重新分配步骤,当它最终适合所有100个元素时,仅使用60%的实际容量。另一方面,在插入之前ensureCapacity(100)
(或使用适当的构造函数重载来实现相同的效果)将使该过程更有效,因为没有多余的未使用容量,并且该阵列只需要重新分配一次。
请注意渐近,上面的两个过程同样是最优的(O(N)
时间和O(N)
空间),但当然后者是一个恒定时间的改进在空间和时间都超过前者。
当然,如果你设置ensureCapacity(10000000)
,并且只插入100个元素,那么你只能使用.001%的容量 - 真是浪费!因此,如果您提前知道要插入多少元素,则可以使用ensureCapacity
使该过程更有效(通过常数因子),但无论如何Vector
仍然可以即使没有你的帮助,它本身也很好。
没有详细说明,这种增长倍增是几何扩展的一种形式,这使Vector
的每次操作能够进行恒定时间摊销分析。值得注意的是ArrayList
,一个由数组支持的类似可扩展数据结构,甚至没有指定其增长策略的细节,但OpenJDK version的增长因子为3/2
。
请注意,Vector
实际上允许您使用capacityIncrement
设置非几何增长因子。 重要的是要认识到,如果将 capacityIncrement
设置为非零的小值,实际上可以使 Vector
执行可怕的操作渐近即可。例如,如果您将其设置为1
,则添加N
元素将是O(N^2)
操作!
ArrayList
不允许您自定义其增长政策,因为您甚至不应该知道(也不关心,真的!)。
elementAt
和get
呢?
直接来自the documentation:
从Java 2平台v1.2开始,这个类被改进以实现
List
接口,使其成为Java Collections Framework的成员。与新的集合实现不同,Vector
是synchronized
。
public E elementAt(int index)
:返回指定索引处的组件。此方法的功能与get(int)
方法(属于List
接口的一部分)相同。
按时间顺序排列,Vector
在elementAt
实施List
之前已经get
,因此必须实施Vector
。
请注意synchronized
为ArrayList
的部分。如果您不需要此功能,{{1}}将是一个更好的选择,因为您没有支付线程安全的费用。
答案 1 :(得分:3)
如果指定零容量或负容量增量,则每次加载矢量的容量,根据capacityIncrement
字段的文档:
容量的数量 矢量是自动的 当它的大小变小时递增 超过其容量。如果 容量增量小于或 等于零,容量 每次需要时,矢量加倍 成长。
如果您只指定容量,则默认capacityIncrement
为零 - 因此加倍行为。
如果你已经很清楚你的收藏需要多大,你就可以指定容量 - 这可以避免不必要的复制。
至于get
和elementAt()
- 是的,为常规集合API添加了elementAt()
。查看实现,除了错误情况中抛出的异常的精确细节之外,它们是相同的。