26

当我做

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 的大小,然后立即使用索引,就像数组一样?

4

8 回答 8

24

这个怎么样:

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

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

于 2013-06-25T15:27:46.620 回答
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到列表末尾,在您的情况下为 : add(1)) 而不是使用 ,这不会发生。或者,如果它适合您,您可以按照另一个答案中的建议将所有元素初始化为 0。

于 2013-06-25T15:36:57.010 回答
3

我认为这里的问题是,尽管您已经建议了 Array 中条目的分配空间,但您实际上并没有创建条目。

返回什么arr.size()

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

于 2013-06-25T15:30:00.600 回答
2

抛开编程不谈,您在这里尝试做的事情是不合逻辑的。

想象一个空的鸡蛋盒,里面有十个鸡蛋的空间。这或多或少是你创造的。然后你告诉一个超级精确和烦人的机器人,你告诉他的到底是什么,用另一个鸡蛋代替第 0 个鸡蛋。机器人报告错误。为什么?他不能替换第0个蛋,因为那里没有蛋!预留了10个鸡蛋的空间,但里面真的没有鸡蛋!

于 2013-06-26T12:30:58.470 回答
1

This is not an Java-specific answer but an data structure answer.

You are confusing the Capacity concept with the Count (or Size) one.

Capacity is when you tell the list to reserve/preallocate a number of slots in advance (in this ArrayList case, you are saying to it create an array of 10 positions) in its' internal storage. When this happens, the list still does not have any items.

Size (or Count) is the quantity of items the list really have. In your code, you really doesn't added any item - so the IndexOutOfBoundException is deserved.

于 2013-06-25T20:12:28.050 回答
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]
于 2013-06-25T15:27:37.783 回答
0

容量用于ArrayList为扩展做准备。循环

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

list 容量开始10。因此,它拥有一个新的Integer[10]内部。随着循环添加到列表中,整数被添加到该数组中。当数组被填充并添加另一个数字时,分配一个新数组的大小两倍于旧数组,并将旧值复制到新数组中。添加一个项目充其量是 O(1),最坏的情况是 O(N)。但是添加 N 个项目将需要2*1024单独的分配:摊销线性时间。

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

于 2013-06-25T20:10:06.147 回答
0

虽然你不能用 arraylist 做你想做的事,但还有另一种选择:Arrays.asList()

于 2013-06-25T16:46:41.607 回答