ArrayList的扩容机制

  一、ArrayList的扩容机制

  1、扩容的计算方式是向右位移,即:newSize = this.size + (this.size>>1)。向右位移,只有在当前值为偶数时,才是除以2;奇数时是抹去最后一位,也就是先减1,然后除以2;附上源码,如下图:

      

  2、扩容的上限:ArrayList的长度并不是没有限制的,它的默认最大长度值是,Integer.MAX_VALUE-8,但是可以突破到 Integer.MAX_VALUE。所以请注意:如果到达ArrayList的默认最大值的时候,扩容不再是1.5倍,而是只增加一个字节,长度达到Integer.MAX_VALUE,如下图的hugeCapacity()方法。此后再进行添加操作,容量是无法扩充了,仍然是Integer.MAX_VALUE,应该无法再添加对象,有兴趣的童鞋可以试试~~~

      

    个人对ArrayList的极限测试,初始容量值不能过大(容易堆内存溢出),也不能太小(扩容次数太多,性能影响太大),另外需要调整虚拟机内存大小,下图就是我的代码:     

       

    ps.

      1、这个位置有点意思 arr.add(Integer.MAX_VALUE+1),本来要放的是Integer类型的,但是括号里按理说已经扩充至long了,编译时不报错。实际结果是变成了-2147483648,也就是Integer.MIN_VALUE,一下子从九重天跌入十八层地狱。。。。

      2、实际上,大家可以试一下,System.out.println(2147483647+1),结果是 -2147483648。除非对其中一个数进行强转成long类型,或者表示为long类型。换句话说,内存类型相对固定(如int),内存占用的位数并不改变,当发生+1操作时,只是在数值上简单+1,当值达到Integer.MAX_VALUE时,最高位是0,再+1高位变成1,也就是最小值,所以不论int类型参数之间不论怎么做加减法运算,永远都是固定的内存空间里发生的变化,取值范围永远在Integer的最大值和最小值的完全闭区间内,因为只有这么大的空间。如果是int碰上long,小的自然服从大的,内存空间必定要发生变化(底层实现决定)。

二、ArrayList容量之最佳实践

  扩容是有成本的,要经历System.arrayCopy(),数组越长成本越高。所以最佳实践是:知道即将放入ArrayList容器的对象数量时,最好能指定合理的初始容量capacity(警告:size和capacity的区别:capacity,即容量,size,容器所盛放对象的数量。通俗的说,假如一个矿泉水瓶(也就是容器,如ArrayList、HashMap)的容量值为600ml,盛放的水量(size)为550ml)。

  ps.集合框架类,有时候也叫容器类,因为它们是存放其他对象(水)的对象(矿泉水瓶)。个人觉得,从白盒的角度看,LinkedList(链表)算不得容器,而更像是火车、地铁车厢之类的链式结构的东西,相互之间环环相扣;但是从黑盒的角度来看,把LinkedList称为容器好像也没毛病,因为看起来可以存放东西。

原文地址:https://www.cnblogs.com/InformationGod/p/9404881.html