一 首先看一下容器的创建构造函数
默认的无参构造 这种创建方式也是我们平时使用最多的一种,会使用一个默认定义好的数组对象
然后看一下这个默认的数组对象是怎么样的
可以看到这个默认数组是静态常量的,也就是说数组内容可以改变,引用不可改变
一个有参构造 参数为指定容器的大小值
1 判断该值是否大于,如果大于则创建指定大小的数组
2 或者值是否等于0,等于零则使用一个默认的数组
3 非法值(小于 0 ) 抛出异常
然后看一下这里的空数组对象
一个有参构造函数 参数为Collection容器对象
1 将传进来的容器转化为数组
2 判断转化后数组的长度是否不等于0
是则判断是否不为Object[].class(这里的主要是防止返回未知类型 )
如果是则创建一个新的Object 数组,长度为容器数组的长度,并将转化候数组的内容拷贝到新数组上。
如果转化后的数组长度等于0 则使用空数组对象
二 容器的数据添加
三个参数的add方法(arg1 添加的元素, arg2 存储数据的数组, arg3 数组当前的长度)
判定数组当前长度是否等于数组的最长容纳长度,是则扩容
否则之间将元素添加数组的最后一个位置(注:最后一个位置是指存储有效数据的位置,并非数组长度最后一个位置)
最后将长度加一
一个参数的add方法
先将modCount的值加1 ,然后调用了三个参数的add方法(参数一: 添加的元素,参数二: 存储数据的数组,参数三,数组当前的长度 ) 然后返回true
两个参数的add方法 该方法主要将元素添插入到指定位置处
1 先检查插入的位置是否合法
2 是则将modCount值加 1
3 然后判断数组当前的长度是否等于数组最大容纳长度,是则扩容,(至于为什么这里扩容的判断逻辑是这样的,我个人认为是为了尽可能的线程安全,虽然这并不是一个线程安全的类)。
4 扩容完成后将插入位置的元素往数组后一个位置开始拷贝
5 最后将元素存放在插入的位置处
6 然后将数组的当前长度值加一
判断插入的位置的逻辑 是否超过了数组当前储存元素的个数或者小于0(非法位置) 是则抛出异常
三 扩容过程
默认扩容(无参) 调用有参的扩容方法,大小为当前的数组长度值加1
也就是默认扩容时只将数组的长度加 1
单个参数扩容(指定容量大小)
1 先获取数组的长度,然后判断数组当前长度是否大于0 或者数组不为静态常量空数组
2 如果是则调用ArraySupport.newLength(arg1 原长度,arg2 指定长度与原长度的差值,长度的两倍) , 然后获取新的长度值,并将数组扩容为新的容量并返回
3 否则取指定的容量大小和默认的容量大小里的最大值作为新数组的大小
也就是说如果使用默认的构造函数并添加第一个元素的话,那么第一次会将容器扩容为 10
ArraySupport.newLength
1 获取差值和旧长度的两倍里的最大值,加上原数组旧长度
2 判断新的长度是否小于数组允许的最大长度值,允许就返回,否则就调用hugeLength
hugeLength
一般来说调用到这个方法说明就是用户对数组扩容时传入的值过大
arg1 差值 arg2 原数组长度
1 将差值与原数组长度相加得出新的长度
2 判断新的长度是否小于零,是则说明发生了溢出,抛出异常
3 否则判断新数组的容量值是否小于最大可扩容值,是则使用数组允许的大最大值,否则使用整形的最大值
数组允许的最大值