Java集合精选常见面试题( 五 )


>(移位运算符):>>1 右移一位相当于除 2,右移 n 位相当于除以 2 的 n 次方 。这里 oldCapacity 明显右移了 1 位所以相当于 oldCapacity /2 。对于大数据的 2 进制运算,位移运算符比那些普通运算符的运算要快很多,因为程序仅仅移动一下而已,不去计算,这样提高了效率,节省了资源
我们再来通过例子探究一下grow() 方法 :
  • 当 add 第 1 个元素时,oldCapacity 为 0,经比较后第一个 if 判断成立,newCapacity = minCapacity(为 10) 。但是第二个 if 判断不会成立,即 newCapacity 不比 MAX_ARRAY_SIZE 大,则不会进入 hugeCapacity 方法 。数组容量为 10,add 方法中 return true,size 增为 1 。
  • 当 add 第 11 个元素进入 grow 方法时,newCapacity 为 15,比 minCapacity(为 11)大,第一个 if 判断不成立 。新容量没有大于数组最大 size,不会进入 hugeCapacity 方法 。数组容量扩为 15,add 方法中 return true,size 增为 11 。
  • 当第16个元素进入容器时再次扩容
这里补充一点比较重要,但是容易被忽视掉的知识点:
  • java 中的 length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了 length 这个属性.
  • java 中的 length() 方法是针对字符串说,如果想看这个字符串的长度则用到 length() 这个方法.
  • java 中的 size() 方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!
hugeCapacity()
从上面 grow() 方法源码我们知道: 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity() 方法来比较 minCapacity 和 MAX_ARRAY_SIZE,如果 minCapacity 大于最大容量,则新容量则为Integer.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 Integer.MAX_VALUE - 8
private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();//对minCapacity和MAX_ARRAY_SIZE进行比较//若minCapacity大,将Integer.MAX_VALUE作为新数组的大小//若MAX_ARRAY_SIZE大,将MAX_ARRAY_SIZE作为新数组的大小//MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}System.arraycopy()Arrays.copyOf()
阅读源码的话,我们就会发现 ArrayList 中大量调用了这两个方法 。比如:我们上面讲的扩容操作以及add(int index,E element)toArray() 等方法中都用到了该方法!
// 我们发现 arraycopy 是一个 native 方法,接下来我们解释一下各个参数的具体意义/***复制数组* @param src 源数组* @param srcPos 源数组中的起始位置* @param dest 目标数组* @param destPos 目标数组中的起始位置* @param length 要复制的数组元素的数量*/public static native void arraycopy(Object src,intsrcPos,Object dest,int destPos,int length);场景:
/*** 在此列表中的指定位置插入指定的元素 。*先调用 rangeCheckForAdd 对index进行界限检查;然后调用 ensureCapacityInternal 方法保证capacity足够大;*再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1 。*/public void add(int index,E element) {rangeCheckForAdd(index);ensureCapacityInternal(size + 1);// Increments modCount!!//arraycopy()方法实现数组自己复制自己//elementData:源数组;index:源数组中的起始位置;elementData:目标数组;index + 1:目标数组中的起始位置; size - index:要复制的数组元素的数量;System.arraycopy(elementData,index,elementData,index + 1,size - index);elementData[index] = element;size++;}

经验总结扩展阅读