Java ArrayList IndexOutOfBoundsException尽管给出了初始容量
当我做
ArrayList arr = new ArrayList(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的大小,然后立即使用索引,就像数组一样?
这是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
类型添加到列表的末尾: add(1)
),这不会发生。 或者,如果它适合您,您可以按照另一个答案中的建议将所有元素初始化为0。
这个怎么样:
ArrayList arr = new ArrayList (Collections.nCopies(10, 0));
这将使用10个零来初始化arr。 然后您可以立即使用索引。
我相信这里的问题是虽然你已经建议在数组中分配条目空间,但你实际上并没有创建条目。
arr.size()
返回什么?
我认为你需要使用add(T)方法。
除了编程之外,你在这里尝试做的事情是不合逻辑的。
想象一个空蛋盒,里面有十个蛋。 这或多或少都是你创造的。 然后你告诉一个超级精确和烦人的,你告诉他的机器人用另一个鸡蛋代替第0个鸡蛋。 机器人报告错误。 为什么? 他无法取代第0个鸡蛋,因为那里没有鸡蛋! 有一个可容纳10个鸡蛋的空间,但里面真的没有鸡蛋!
您可以使用arr.add(1)
,它将在第一个空单元格中添加1
,即0索引的单元格。
或者您可以创建自己的列表:
public static class PresetArrayList extends ArrayList { private static final long serialVersionUID = 1L; public PresetArrayList(int initialCapacity) { super(initialCapacity); addAll(Collections.nCopies(initialCapacity, (E) null)); } }
然后:
List list = new PresetArrayList (5); list.set(3, 1); System.out.println(list);
打印:
[null, null, null, 1, null]
这不是Java特定的答案,而是数据结构的答案。
您将Capacity
概念与Count
(或Size
)混淆。
容量是当你告诉列表预先保留/预分配多个插槽(在这个ArrayList的情况下,你说它创建一个10个位置的数组)在它的’ 内部存储器中 。 发生这种情况时,列表仍然没有任何项目。
大小(或计数)是列表实际具有的项目数量。 在您的代码中,您确实没有添加任何项 – 因此IndexOutOfBoundException是值得的。
虽然你不能用arraylist做你想做的事,但还有另一种选择:Arrays.asList()
容量用于准备ArrayList
以进行扩展。 循环
List 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
个人分配:摊销线性时间。
容量不是大小。 如果尚未添加到数组列表中,则大小将为零,并且尝试写入第3个元素将失败。