ArrayList就是数组列表,主要用来装载数据,当我们装载的是基本类型的数据int,long,boolean,short,byte…的时候我们只能存储他们对应的包装类,它的主要底层实现是数组Object[] elementData。
与它类似的是LinkedList,和LinkedList相比,它的查找和访问元素的速度较快,但新增,删除的速度较慢。
小结:ArrayList底层是用数组实现的存储。
特点:查询效率高,增删效率低,线程不安全。使用频率很高。
因为我们正常使用的场景中,都是用来查询,不会涉及太频繁的增删,
如果涉及频繁的增删,可以使用LinkedList,如果你需要线程安全就使用Vector,
这就是三者的区别了,实际开发过程中还是ArrayList使用最多的。
不存在一个集合工具是查询效率又高,增删效率也高的,还线程安全的,至于为啥大家看代码就知道了,因为数据结构的特性就是优劣共存的,想找个平衡点很难,牺牲了性能,那就安全,牺牲了安全那就快速。
ArrayList可以通过构造方法在初始化的时候指定底层数组的大小。
通过无参构造方法的方式ArrayList()初始化,则赋值底层数Object[] elementData为一个默认空数组Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}所以数组容量为0,
只有真正对数据进行添加add时,才分配默认DEFAULT_CAPACITY = 10的初始容量。
大家可以分别看下他的无参构造器和有参构造器,无参就是默认大小,有参会判断参数。
其实实现方式比较简单,他就是通过数组扩容的方式去实现的。
就比如我们现在有一个长度为10的数组,现在我们要新增一个元素,发现已经满了,那ArrayList会怎么做呢?
第一步他会重新定义一个长度为10+10/2的数组也就是新增一个长度为15的数组。
然后把原数组的数据,原封不动的复制到新数组中,这个时候再把指向原数的地址换到新数组,ArrayList就这样完成了一次改头换面。
因为ArrayLIst的默认初始值大小是10,所以这里用10举例。
然后你们也可以看到,他的构造方法,如果你传入了初始值大小,那就使用你传入的参数,如果没,那就使用默认的,一切都是有迹可循的。
据说是因为sun的程序员对一系列广泛使用的程序代码进行了调研,结果就是10这个长度的数组是最常用的最有效率的。
也有说就是随便起的一个数字,8个12个都没什么区别,只是因为10这个数组比较的圆满而已。
他有指定index新增,也有直接新增的,在这之前他会有一步校验长度的判断ensureCapacityInternal,
就是说如果长度不够,是需要扩容的。
在扩容的时候,老版本的jdk和8以后的版本是有区别的,8之后的效率更高了,采用了位运算,右移一位,其实就是除以2这个操作。
指定位置新增的时候,在校验之后的操作很简单,就是数组的copy,大家可以看下代码。
不知道大家看懂arraycopy的代码没有,我画个图解释下,你可能就明白一点:
比如有下面这样一个数组我需要在index 5的位置去新增一个元素A