Java ArrayList IndexOutOfBoundsException尽管给出了初始容量

时间:2013-06-25 15:25:06

标签: java arrays arraylist

当我这样做时

ArrayList<Integer> arr = new ArrayList<Integer>(10);
arr.set(0, 1);

Java给了我

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.ArrayList.rangeCheck(Unknown Source)
    at java.util.ArrayList.set(Unknown Source)
    at HelloWorld.main(HelloWorld.java:13)

有没有一种简单的方法可以预先保留ArrayList的大小,然后立即使用索引,就像数组一样?

8 个答案:

答案 0 :(得分:24)

这个怎么样:

ArrayList<Integer> arr = new ArrayList<Integer>(Collections.nCopies(10, 0));

这将使用10个零来初始化arr。然后您可以立即使用索引。

答案 1 :(得分:14)

以下是ArrayList的来源:

构造函数:

public ArrayList(int initialCapacity) 
{
     super();

     if (initialCapacity < 0)
          throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
     this.elementData = new Object[initialCapacity];
}

您致电set(int, E)

public E set(int index, E element) 
{
     rangeCheck(index);  
     E oldValue = elementData(index);
     elementData[index] = element;
     return oldValue;
}

Set来电rangeCheck(int)

private void rangeCheck(int index) 
{
    if (index >= size) {
         throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
}

它可能很微妙,但是当您调用构造函数时,尽管初始化了Object[],但您没有初始化size。因此,从rangeCheck开始,您获得IndexOutOfBoundsException,因为size为0.而不是使用set(int, E),您可以使用add(E e)(添加e类型为E的{​​{1}},在您的情况下:add(1)),这不会发生。或者,如果它适合您,您可以按照另一个答案中的建议将所有元素初始化为0。

答案 2 :(得分:3)

我认为这里的问题是虽然您已经建议在数组中分配条目空间,但实际上并没有创建条目。

arr.size()返回什么?

我认为您需要使用add(T)方法。

答案 3 :(得分:2)

除了编程之外,你在这里尝试做的事情是不合逻辑的。

想象一个空蛋盒,里面有十个蛋。这或多或少都是你创造的。然后你告诉一个非常精确和令人讨厌的机器人,你用什么告诉他机器人用另一个鸡蛋代替第0个鸡蛋。机器人报告错误。为什么?他无法取代第0个鸡蛋,因为那里没有鸡蛋!有一个可容纳10个鸡蛋的空间,但里面确实没有鸡蛋!

答案 4 :(得分:1)

您可以使用arr.add(1),这会在第一个空单元格中添加1,即0索引的单元格。

或者您可以创建自己的列表:

public static class PresetArrayList<E> extends ArrayList<E> {

    private static final long serialVersionUID = 1L;

    public PresetArrayList(int initialCapacity) {
        super(initialCapacity);
        addAll(Collections.nCopies(initialCapacity, (E) null));
    }

}

然后:

List<Integer> list = new PresetArrayList<Integer>(5);
list.set(3, 1);
System.out.println(list);

打印:

[null, null, null, 1, null]

答案 5 :(得分:1)

这不是Java特定的答案,而是数据结构的答案。

您将Capacity概念与Count(或Size)概念混淆。

容量就是当你告诉列表预先保留/预分配多个插槽时(在这个ArrayList的情况下,你要说它在' 10 位置的数组) > 内部存储 。发生这种情况时,列表仍然没有任何项目。

大小(或计数)是列表实际拥有的项目数量。在你的代码中,你真的没有添加任何项 - 所以IndexOutOfBoundException是值得的。

答案 6 :(得分:0)

虽然你无法用arraylist做你想做的事,但还有另外一个选择:Arrays.asList()

答案 7 :(得分:0)

容量用于准备ArrayList以进行扩展。采取循环

List<Integer> list = new ArrayList<>();
for(final int i = 0; i < 1024; ++i) {
    list.add(i);
}

list starts off,容量为10。因此它内部有一个新的Integer[10]。当循环添加到列表中时,整数将添加到该数组中。当数组被填充并且添加了另一个数字时,新数组的大小是旧数组的两倍,旧值被复制到新数组。添加项目最多为O(1),最差为O(N)。但添加N个项目将需要约2*1024个人分配:摊销线性时间。

容量不是大小。如果尚未添加到数组列表中,则大小将为零,并且尝试写入第3个元素将失败。