ArrayList的add(index,object)方法抛出IndexOutOfBoundException

时间:2015-03-24 10:17:43

标签: java arraylist data-structures collections

使用下面提到的代码片段创建arrayList:

List arrayList = new ArrayList(16);

ArrayList的内部实现创建一个大小为16的数组elementData,并在每个位置分配null。在执行arrayList.add(2,"HelloWorld")之类的操作时, IndexOutOfBoundException 作为添加元素的索引(即2)大于 size < / strong> arrayList的属性。

从javaDocs可以清楚地看出,在size初始化时,arrayList的 arrayList 属性被初始化为0,并且每次添加新元素时都会增加1到arrayList

有人可以解释,为什么 ArrayList 数据结构首先是以这种方式设计的。甚至'内部dataStructure elementData 在创建arrayList时初始化为16个空值,但仍然不允许在indeces处添加值&gt;尺寸; (假设在这种情况下索引<16)。实现add(index,object)的想法是什么 功能由arrayList的size属性控制?

5 个答案:

答案 0 :(得分:2)

使用大小大于List.size()的内部数组的目的是避免不必要地重新分配数组。如果内部数组总是与List具有相同的大小,那么每次添加新元素时,都必须重新分配内部数组,从而导致性能下降。

答案 1 :(得分:1)

实际上,ArrayList的默认构造函数构造了一个初始容量为10的列表。

public ArrayList() {
    this(10);
} 

但为什么我们需要这样的分配呢?如您所知,如果您事先指明ArrayList的大小,则可以为列表提供高效率。否则,在元素数量超过ArrayList的初始容量后,将对每个元素执行新的重新分配操作。

documentation说:

  

public void add(int index,E element)

     

<强>抛出:

     

IndexOutOfBoundsException -   如果索引超出范围   (index&lt; 0 || index&gt; size())

如您所见,它会抛出IndexOutOfBoundsException if(index&gt; size())。 由于ArrayList的“public int size()”返回的元素不等于null,因此您的大小等于0(不是您在示例中所说的16)。换句话说,如果计算了空值,则使用默认构造函数创建的每个ArrayList的大小将为10.

因此,“arrayList.add(2,”HelloWorld“)”抛出IndexOutOfBoundsException,因为index = 2但size()= 0。

编辑:

我认为当你挂载你的论点时,你用它作为基础:

String[] arr = new String[5];
arr[3] = "hello";

System.out.println(arr[3]); 

然后,您认为为什么可以直接在数组元素中赋值,但为什么在使用ArrayList的add(int index,E element)方法时不能做同样的事情。实际上,这是真的,但没有条件将ArrayList实现为Array的完整对应物。换句话说,该方法以该规则为条件,因为它是ArrayList的本质。众所周知,在创建数组时,请在方括号中指定其大小。将int作为参数的ArrayList的构造函数不会做同样的事情。它只执行一个虚构的分配。是的,它可以使用此分配指定其初始大小,或者在调用add(int index,E element)之后,size可以增加1。但是,实现ArrayList是为了提供类似于数组的结构,该结构在索引号方面具有连续性,但没有固定的大小。因此,还有一些其他更高级别的抽象示例执行此任务。举例来说,LinkedHashMap结构。

答案 2 :(得分:0)

您不能在特定索引处添加对象,直到它包含null。您只需要使用add方法添加对象,然后就可以更新索引的值。

例如。

 ArrayList<Integer> arrlist = new ArrayList<Integer>(5);

// use add() method to add elements in the list
arrlist.add(15);
arrlist.add(22);
arrlist.add(30);
arrlist.add(40);

// adding element 25 at third position
arrlist.add(2,25);

答案 3 :(得分:0)

您很少需要指定ArrayList容量,只有当您知道ArrayList将保留多少元素时,它才能提高效果。

ArrayList只是List,可以自动增长或缩小。使用List从不需要在地方n添加元素,如果列表为空,您只需链接到上一个节点(除非它是当然的头) - 这是ArrayList的想法,除了它可以自动增长/缩小的事实。

答案 4 :(得分:0)

请参阅ArrayList的{​​{3}}方法的java文档。您可以在此处找到ArrayIndexOutOfBound时发生的if the index is out of range (index < 0 || index > size())例外情况。

您声明了ArrayList初始容量为16.这并不意味着ArrayList的16个索引位置中的每一个都包含元素。它只是提到初始容量,并在必要时动态增加它的大小。

ArrayList类 -

中查看构造函数的源代码
/**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param   initialCapacity   the initial capacity of the list
     * @exception IllegalArgumentException if the specified initial capacity
     *            is negative
     */
    public ArrayList(int initialCapacity) {
    super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
           this.elementData = new Object[initialCapacity];
    }

在这里,我们找不到任何告诉我们的内容 - ArrayList将以null值启动。

更新:根据你的评论,我做了一些实验,因为我不确定引用/非基本类型的数组是否会用null初始化。请参阅以下代码。通过在每次执行时取消注释每一行来运行代码 -

import java.util.List;
import java.util.ArrayList;

public class ArrayListTest{

    public static void main(String[] args){

        List<String> list1 = new ArrayList<String>(); //default with initial capacity 10
        List<String> list2 = new ArrayList<String>(5);
        List<String> list3 = new ArrayList<String>(5);

        list2.add(null);
        list2.add(null);
        list2.add(null);

        list3.add("zero");
        list3.add("one");
        list3.add("two");

        //System.out.println(list1.get(4)); //IndexOutOfBoundException

        //System.out.println(list2.get(0)); //null
        //System.out.println(list2.get(2)); //null;
        //System.out.println(list2.get(3)); //IndexOutOfBoundException

        //System.out.println(list3.get(0)); //zero
        //System.out.println(list3.get(2)); //two;
        //System.out.println(list3.get(3)); //IndexOutOfBoundException
        //list3.add(4, "four"); //IndexOutOfBoundException

    }

}

在这里,您可以看到list2.get(0)list2.get(2)为空。因为我们把null放在这些索引上。但是list2.get(3)没有给null,因为我们没有将null放在索引3处。所以似乎参数/非基本类型的数组不会用{{1}初始化}。 null给出list2.get(3)

您找到IndexOutOfBoundException的相同方案,我没有在此列表中添加任何list3.。即使我们尝试在null的索引4处添加一些值,它也会list3。由于索引4不适用于IndexOutOfBoundException。但您可以在list3的索引2处添加一些值。在此列表的索引2处的原因我已手动插入list2

所以长话短说(我认为) - null不会使用new ArrayList<SomeType>(givenSize)初始化数组,并将所有元素设置为givenSize

希望它会有所帮助。
谢谢。