Java ArrayList 的 ensureCapacity 方法无效

20

我可能做错了,或者我不理解这个方法是如何工作的。

ArrayList<String> a = new ArrayList<String>();
a.ensureCapacity(200);
a.add(190,"test");
System.out.println(a.get(190).toString());

我原本认为ensureCapacity会让我插入一个索引值高达那个容量的记录。还有其他方法可以实现这个吗?

第三行代码出现了IndexOutOfBounds错误。

8个回答

40
不,ensureCapacity并不会改变一个ArrayList的逻辑大小(logical size),它只会改变容量(capacity),也就是列表在下次需要复制值之前可以达到的大小。
你需要非常注意逻辑大小和容量之间的区别。逻辑大小指的是所有范围在[0, size)内的值都是可访问的,并且添加新元素会将其添加到索引size处。而容量更像是实现细节——它是用于存储的后备数组的大小。
调用ensureCapacity应该只会在性能方面产生影响(通过避免过度复制),它并不会影响列表中的逻辑模型,如果你明白我的意思的话。
编辑:听起来你想要一种类似于ensureSize()的方法,可能会长这样:
public static void ensureSize(ArrayList<?> list, int size) {
    // Prevent excessive copying while we're adding
    list.ensureCapacity(size);
    while (list.size() < size) {
        list.add(null);
    }
}

那是根据我看到的结果所考虑的...但是有没有办法做我需要做的事情呢? - kralco626
如果你真的想在位置190上只有一个项目,请使用数组。 - Jan Zyka
1
也许可以使用不同的类而不是ArrayList? - kralco626
没错,伙计们:我纠正了一个打字错误。毫无疑问,这是我职业生涯的巅峰。 - James Johnson
@JamesJohnson:很抱歉让你失望,但那不是打字错误。它是一个具有包含起始点和排除终点的范围——索引“size”本身在任何时候都超出有效值范围。 - Jon Skeet
3
我的游行结束了。谢谢Jon。现在我得想办法告诉我的孩子们 ;) - James Johnson

5

正如其他人提到的那样,ensureCapacity 不是用于这个目的的。看起来你想要从 200 个空值开始使用 ArrayList? 那么这是最简单的方法:

ArrayList<String> a = new ArrayList<String>(Arrays.asList( new String[200] ));

如果你想用"test"替换元素190,则可以执行以下操作:

a.set(190, "test");

这与

之前的不同。
a.add(190, "test");

这将在索引190处添加“test”,并将其他9个元素向上移动,导致列表大小为201。

如果您知道始终会有200个元素,最好使用数组。


+1,但我只是举了一个简单的例子,出现了与我的实际情况相同的错误。谢谢。 - kralco626

4

确保容量不是向列表中添加项目。只有在已经添加了191个元素后,才能获取第190个元素或在第190个元素处添加元素。 "容量"只是ArrayList在需要调整其内部数据结构(数组)大小之前可以容纳的对象数量。如果ArrayList具有getCapacity()方法,则可以执行以下操作:

ArrayList<String> a = new ArrayList<String>();
a.ensureCapacity(200);
System.out.println(a.size());
System.out.println(a.getCapacity());

分别会打印出0和大于等于200的某个数字


2

ArrayList将其容量(内部数组的大小)与其大小(添加的元素数量)分别维护,而“set”方法依赖于索引已分配给元素。没有设置大小的方法。如果您需要这样做,可以使用循环添加虚拟元素:

for (int i = 200; --i >= 0;) a.add(null);

0
  public static void fillArrayList(ArrayList<String> arrayList, long size) {
    for (int i = 0; i < size + 1; i++) {
      arrayList.add(i,"-1");
    }
  }

public static void main(String[] args) throws Exception {
  ArrayList<String> a = new ArrayList<String>(10);
  fillArrayList(a, 190);
  a.add(190,"test");
  System.out.println(a.get(190).toString());
}

0

向 ArrayList 添加 190 个空条目似乎是对数据结构的误用。

  1. 考虑使用标准基本数组。

  2. 如果您需要泛型或想要更有效地使用空间,则可以考虑使用 SparseArray 或甚至像 HashMap 这样的 Map 可能适合您的目的。


0

再次使用JavaDoc来澄清情况:

Throws: IndexOutOfBoundsException 
    - if index is out of range (index < 0 || index > size()).

请注意,size() 返回列表当前持有的元素数量。

0

ensureCapacity 只是确保底层数组的容量大于或等于参数。它不会改变 ArrayList 的大小。它不会通过 API 显示任何更改,因此您不会注意到任何差异,除了在 ArrayList 调整其内部数组之前可能需要更长的时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接