有⽤过,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的初始容量。 ⼤家可以分别看下他的⽆参构造器和有参构造器,⽆参就是默认⼤⼩,有参会判断参数。
其实实现⽅式⽐较简单,他就是通过数组扩容的⽅式去实现的。
默认是具体说是调研发现的,arrayList1.7开始变化有点⼤,⼀个是初始化的时候,1.7以前会调⽤this(10)才是真正的容量为10,1.7即本身以后是默认⾛了空数组,只有第⼀次add的时候容量会变成10。
他有指定index新增,也有直接新增的,在这之前他会有⼀步校验⻓度的判断 ensureCapacityInternal,就是说如果⻓度不够,是需要扩容的。 在扩容的时候,⽼版本的jdk和8以后的版本是有区别的,8之后的效率更⾼了,采⽤了位运算,右移⼀位,其实就是除以2这个操作。 1.7的时候3/2+1 ,1.8直接就是3/2 指定位置新增的时候,在校验之后的操作很简单,就是数组的copy,⼤家可以看下代码。 ⽐如有下⾯这样⼀个数组我需要在index 5的位置去新增⼀个元素A 那从代码⾥⾯我们可以看到,他复制了⼀个数组,是从index 5的位置开始的,然后把它放在了index5+1的位置 给我们要新增的元素腾出了位置,然后在index的位置放⼊元素A就完成了新增的操作了
⾄于为啥说他效率低,只是在⼀个这么⼩的List⾥⾯操作, 要是我去⼀个⼏百⼏千⼏万⼤⼩的List新增⼀个元素, 那就需要后⾯所有的元素都复制, 然后如果再涉及到扩容啥的就更慢了不是嘛。会初始化数组⼤⼩!但是List的⼤⼩没有变,因为list的⼤⼩是返回size的。 ⽽且将构造函数与initialCapacity结合使⽤,然后使⽤set()会抛出异常,尽管该数组已创建,但是⼤⼩设置不正确。
取决于你删除的元素离数组末端有多远,ArrayList拿来作为堆栈来⽤还是挺合适的,push和pop操作完全不涉及数据移动操作。 那他的删除怎么实现的呢? 删除其实跟新增是⼀样的,不过叫是叫删除,但是在代码⾥⾯我们发现,他还是在copy⼀个数组。 继续打个⽐⽅,我们现在要删除下⾯这个数组中的index5这个位置 那代码他就复制⼀个index5+1开始到最后的数组,然后把它放到index开始的位置 index5的位置就成功被”删除“了其实就是被覆盖了,给了你被删除的感觉。 同理他的效率也低,因为数组如果很⼤的话,⼀样需要复制和移动的位置就⼤了。
适合做队列吗? ArrayList的遍历和LinkedList遍历性能⽐较如何?
论遍历ArrayList要⽐LinkedList快得多, ArrayList遍历最⼤的优势在于内存的连续性, CPU的内部缓存结构会缓存连续的内存⽚段, 可以⼤幅降低读取内存的性能开销。ArrayList就是动态数组,⽤MSDN中的说法,就是Array的复杂版本, 它提供了动态的增加和减少元素,实现了ICollection和IList接⼝, 灵活的设置数组的⼤⼩等好处。