ArrayList注意事项
可以存储空值,但是遍历会出错
ArrayList存储数据底层由数组来实现
ArrayList基本等同于Vector,但是ArrayList是线程不安全的,多线程不建议使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;import java.util.List;public class Test { public static void main (String [] args) { Dog dog1=new Dog ("ahhua" ,12 ); Dog dog2=new Dog ("a" ,15 ); Dog dog3=new Dog ("ah" ,13 ); Dog dog4=new Dog ("ah" ,13 ); List list=new ArrayList (); list.add(dog2); list.add(dog1); list.add(dog2); list.add(null ); for (Object o :list) { System.out.println(o.toString()); } } } class Dog { private String name; private int age; public Dog (String name, int age) { this .name = name; this .age = age; } @Override public String toString () { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}' ; } }
ArrayList的底层结构和源码分析 无参构造器的扩容 首先我们运行以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import java.util.ArrayList;import java.util.Collection;import java.util.Iterator;import java.util.List;public class Test { public static void main (String [] args) { ArrayList arrayList=new ArrayList (); for (int i=0 ;i<=10 ;i++){ arrayList.add(i); } for (int i=11 ;i<15 ;i++){ arrayList.add(i); } } }
但我们调用无参构造器时,调用了以下方法,并且定义的类型为Object[]数组类型,我们可以确认ArrayList的底层使用的是数组存储
我们可以看到在运行到add方法时,进入到了一个boolean的方法,此方法先决定是否要进行扩容,而add方法的第一行的函数如下一张图
首先判断该存储的数组是否为空,如果为空,则进行比较,并且选取两个数的一个最大数作为初始集合的大小,应该为10。而该方法的最后一行的代码,则是确定是否还进行底层扩容,大于minCapacity则进行扩容。
当我们决定扩容时,则调用下面的函数,扩容为原来的1.5倍,而copyof方法会保持地址不变,直接增加数。
当我们运行之后
15个空间不够时,我们许需要扩容,扩容之后
其实在这个过程中进行扩容这么大,是因为在这个arraylist添加和删除的过程中,成本比较大,每一次添加个删除都要不可避免的移动元素,保证空间的连续性,每一次大小变为原来的两倍,避免不得不再一次改变容量
有参构造器 有参构造器,我们可以给他附上初始值,而每一次扩容依然是原来的1.5倍,运行的原理和上面的一样,只是初始值为我们赋值的那个数,而不是10.