JAVA集合系列分享-ArrayList(java集合超详解)
Collection学习分享:集合在我们日常开发中是经常用到的,用来存储一些对象,借助jdk提供的集合我们可以很方便的进行一些遍历,查找,删除,排序等操作(jdk版本为1.8)。
首先简单学习下Arraylist,借助idea等工具查看它的继承关系图(idea中的快捷键为Ctrl+shift+Alt+u),可以看到Arraylist实现了List接口,List又继承自Collection接口(见图1),
我们重点关注下Arraylist的创建过程,元素的添加、删除等操作。
1.ArrayList的创建:ArraylIst常用的两个构造器见图2,一个是无参构造器,图3绿框可以看到无参构造器中将默认的长度为0的Object[]数组赋值给elementData,后面add操作时可以看到ArrayList底层是Object[]数组来存储元素。另一个是有参构造器,传入一个初始容量,initialCapacity>0时直接创建长度为initialCapacity的数组,initialCapacity=0时还是将长度为0的数组(见图3红色框)赋值给elementData。(java调用子类构造器时会隐式调用父类无参构造器,由于ArrayList的父类无参构造没做什么事也就不讨论了)
2. add(E)操作:添加操作顾名思义就是将元素add到集合里,见图4可以看到分为两步走,第一步就是我们在创建集合时已经知道底层是用Object[]数组来存储元素的,而我们知道java中数组是不能自动扩容的,所以在add元素时要确保数组不越界,在ensureCapacityInternal()方法中去确保 Object[]数组有足够的长度,如果长度不够则会进行扩容操作。第二步就是将需要添加的元素存储到elementData数组的坐标为size处,如elementData数组长度为5,已经添加了2个元素则size为2,此时添加的元素就在下标为size+1=3处。还有add(int,E)将元素添加到指定位置。
注意:从图5可以看到当用无参构造器和有参但参数为0时,第一次add元素时会进行扩容操作,因为此时的elementData就是默认的所以进行Math.max()运算,此时的minCapacity=1,DEFAULT_CAPACITY=10见图6,计算结果为10,所以创建的Object[]数组长度为10。(面试有被问到初始化容量为多少,感觉这样回答更严谨些(jdk版本为1.8))
3. remove(E)操作:从图7可以看到在进行remove操作时,先判断是否为null,然后循环数组找出需要移除的元素,可以看到index从0开始且移除后进行return,所以remove只能按顺序移除第一个相同的元素。找到需要移除元素的index进行fastRemove(index)见图8,移除操作其实是用后面的元素覆盖掉要被移除的元素,所以numMoved为被移除元素后面剩余元素数量,然后用arrayCopy完成覆盖,因为arrayCopy操作最后的元素会多余所以elementData[--size]将末尾多余的元素置为 null。
4. get(index): get操作比较简单,先判断index是否越界见图10,然后从Object[]数组中根据index取值。
总结:1.ArrayList基于数组实现的,无容量限制;
2. ArrayList扩容时会创建新的数组然后将老数组元素copy过去;
3. 从图中代码可以看到Arraylist并不是线程安全的。