阅读ArrayList 源码注意的一个点总结

259 阅读3分钟

在阅读ArrayList源码的时候需要注意点. (1)在ArrayList是支持序列化的 但是存储对象的数组elementData 是不支持序列化的。通过 transient 修饰的 众所周知 经过transient 修饰的字段是不支持序列化的(不是不能序列化如果想序列化也可以。),主要原因是该字段是数据作为数组缓冲区相当于零食存储用的数组。支持数据扩容,所以里面可能会有一些空对象,不适合全部序列化成二进制对象。另外提供方法支持反序列化和序列化 注意 这里用的是size()长度而不是elementData的长度

反序列化后数组的长度和缓冲区的长度是一致的

(2)关于扩容的问题 存在一个最大扩容限度由于所有的对象存在内存中,所能存储的长度和局体的内存设置有关,list只提供了一个理论最大值MAX_ARRAY_SIZE 。 关于扩容 最大长度 MAX_ARRAY_SIZE ,是整数的最大常数减去八,我们知道一个对象的对象头会被分配8个字节分别是 Mark Word(4个字节),class对象指针占用4个字节(在这里会有32位和64位虚拟机的区分,有些虚拟机用来了指针压缩技术对64 为虚拟机的指针空间进行压缩,采用时间换空间的策略)。这样可以预防OutOfMemoryError堆溢出,存在概率性问题,堆溢出诱发因素有很多。在创建对象的时候默认最大数组长度可能不会引起对内存溢出。具体情况和虚拟机的内存设置有关

(3)关于get 元素从0 开始不是从1开始,这个问题本身包含有一个问题那就是如何取ArrayList中存到元素的问题。ArrayList数组中存放数据的结构用的是数组,数组查找元素用的是偏移量,而偏移量是从0 开始的,如果数据量比较大的话每次取数据都从1 开始那么取数据都会减一,造成额外的运算。 (4)关于优化部分,数据的扩容采用的是位运算 ,新的长度 等于原来的长度的3/2, oldCapacity + (oldCapacity >> 1),如果超过了int的最大值,就会变成负数这个时候针对负数情况作了一个特列处理看截图后5行代码

(5)为了优化整个list 的功能 ArrayList对获取元素进行了优化,在原来的基础上扩充了部分功能,加入了 fast-fail 校验,这是一个预防机制不能保证一定会发生在,迭代获取ArrayList 元素的的时候,防止同时修改数组的长度,这个时候西安校验数组长度是否会发生变化,如果法还是能变化的话,直接抛错以防带来问题,保持整个对象长度的完整形(注意不能保证整个数组保存的数据不被改变),第二处优化是整个对象创建采用了懒加载方式,每次创建对象如果没有指定长度的话默认创建一个空数组来存储。需要的时候再扩容。

(6)在获取数据方面做了一个扩充实现了RandomAccess 接口,RandomAccess接口本省没有任何实现方法,具体的方法由实现类来实现语义。支持快速随机访问