繁体   English   中英

Java ArrayList <Double> IndexOutOfBoundsException问题

[英]Java ArrayList<Double> IndexOutOfBoundsException Problem

我有一个ArrayList的问题。 我需要它来存储结果。 因为我想从元素n开始,我试图给ArrayList一个带有ensureCapacity(n+1)的容量来使用set(n,x)但是我得到一个IndexOutOfBoundsException

我尝试在使用set之前存储n add(x) ,这是有效的。

所以我想知道为什么它在我的路上不起作用以及如何解决这个因为把n次add(x)不是一个好的风格;-)

当您更改ArrayList的容量时,它不会创建任何元素,它只会保留可能存在元素的内存。 您可以在调整容量之前和之后检查尺寸,您会发现它没有变化。

更改容量的目的是,如果您事先知道您将拥有多少元素,那么您可以在添加新元素时避免不必要的重复调整大小,并且可以避免因未使用的容量过多而浪费内存。

如果您不喜欢直接使用自己的循环和列表add方法,那么还有另一种方法。 使用您想要的元素数创建您的ArrayList ,如下所示:

final int MAX_ELEMENTS = 1000;
List<Integer> myList = new ArrayList<Integer>(
    Collections.<Integer>nCopies(MAX_ELEMENTS, null));

或者,如果您已经有一个列表要扩展n元素的大小:

myList.addAll(Collections.<Integer>nCopies(n, null));

(注意,我在这里假设列表将包含Integer对象,但您可以将其更改为自定义类型。如果您使用的是raw / pre-Java 5类型,则只需删除泛型声明。)

至于你的实际问题:容量!=内容。 ArrayList内部同时具有物理数组和实际数据。 增加容量,更改内部数组,以便它可以容纳那么多元素,但是,计数不会改变。 您需要添加元素以增加计数。

另一方面,如果您只是尝试设置特定元素并知道要使用的最大值,为什么不直接使用数组? 如果您需要将此数组传递给采用List的API,则使用Arrays.asList 其他类仍然可以更改后备阵列的内容,但它无法增加它的大小或容量。

正如其他人已经回答的那样, ensureCapacity()只与性能有关,并不是普通用户经常使用的。

来自Bruce Eckel的Thinking in Java书籍:

在私人消息中,Joshua Bloch写道:“...我认为我们错误地将实现细节(例如散列表大小和加载因子)放入我们的API中。客户端应该告诉我们集合的最大预期大小,我们应该从那里开始。通过选择这些参数的值,客户很容易弊大于利。作为一个极端的例子,考虑Vector的capacityIncrement。没有人应该设置这个,我们不应该提供它。如果你将它设置为任何非零值,一系列附加的渐近成本从线性到二次。换句话说,它会破坏你的表现。随着时间的推移,我们开始明智地对待这类事情。如果你看看IdentityHashMap,你会发现它没有低级调整参数“

您正在获得此异常,因为ensureCapacity()仅确保分配足够的内存以将对象添加到ArrayList,我相信这是为了您想要一次添加多个对象,而无需重新定位内存。

要做你想做的事,你必须先用null元素启动ArrayList ...

int n = 10;  //capacity required
ArrayList foo = new ArrayList();

for( int i=0; i<=n; i++ ) {
      foo.add(null);
}

然后,List中有对象可以通过索引引用,并且不会收到异常。

ensureCapacity()有另一个目的。 它应该用于在构建List之后了解List所需大小的情况。 如果你知道构造函数之前的大小,只需将它作为参数传递给构造函数。

在前一种情况下,使用ensureCapacity()可以在每次添加时保存后备阵列的多次复制。 但是,使用该方法会使结构处于看似不一致的状态

  • 后备阵列的大小增加
  • ArrayList上的size字段不是。

然而,这是正常的,因为容量!=大小

使用add(..)方法,这是增加size字段的唯一方法:

ArrayList list = new ArrayList();
list.ensureCapacity(5); // this can be done with constructing new ArrayList(5)

for (int i = 0; i < list.size - 1; i ++) {
   list.add(null);
}
list.add(yourObject);

也许您应该重新考虑使用List<Double>的选择。 如果要以奇数顺序添加元素,那么Map<Integer,Double>可能更合适。

这是否合适取决于您目前没有使用的有关您的使用情况的知识。

数据结构最终会被完全填充,还是数据稀疏?

其他人对EnsureCapacity()的评价......

你应该写一个像DynamicArrayList extends ArrayList这样的类。 然后只需覆盖add(n,x)来处理指定的for循环add(null)逻辑。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM