前两天看java源码,看到ArrayList的add函数。
ArrayList中是用数组保存数据的,add函数如下:
1 public void add(int index, E element) { 2 rangeCheckForAdd(index); //教研index是否超出范围 3 4 ensureCapacityInternal(size + 1); // 由于要添加新元素,这里需要确保数组大小满足size+1 5 System.arraycopy(elementData, index, elementData, index + 1, 6 size - index); //拷贝移位 7 elementData[index] = element; //将新元素放在指定位置 8 size++; //增加size 9 }
这里我对这个System.arraycopy 比较感兴趣,因为这里是从一个数组拷贝到同一个数组,竟然不担心会出现拷贝错误的情况。
下意识以为 System.arraycopy实现方式是这样:
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) { for(int i=0;i<length;i++) { dest[destPos+i] = src[srcPos+i]; } }
如果这个函数按照上面这样设计,那么可能会出现错误:
设原先数组为
Integer[] array = {obj0, obj1, obj2, obj3},
若执行上面设计的代码,那么执行完 System.arrayCopy(array, 0, array, 1, 3);之后,
按照推断array的结果应该为
array == {obj0, obj0, obj0, obj0};
但是,事实上这个函数却没有出错:
java提供的System.arrayCopy函数却能正确的得到 {obj0, obj0, obj1, obj2}
带着好奇,查看System.arraycopy()函数注释,得到下面这段:
* If the <code>src</code> and <code>dest</code> arguments refer to the * same array object, then the copying is performed as if the * components at positions <code>srcPos</code> through * <code>srcPos+length-1</code> were first copied to a temporary * array with <code>length</code> components and then the contents of * the temporary array were copied into positions * <code>destPos</code> through <code>destPos+length-1</code> of the * destination array.
意思就是,如果src与dest是同一个数组(设为array),那么这个函数执行起来就像是先把array的内容拷贝到一个相同大小的临时数组(设为tmp),
再将数据从tmp的srcPos~srcPos+length-1拷贝到array的destPos~destPos+length-1。
在拷贝过程,tmp保存了和原先数组相应的对象引用顺序,因此拷贝对象指针时才不会出现顺序错乱的情况。