数组的底层的底层原理更加复杂,源码难寻,只知道数组自带了两个方法,一个是length(),一个是clone(),并没有remove()
于是我就在思考如何去除掉数组中的某个元素
方法1是觉得让数组变成ArrayList集合之后再remove,因为ArrayList集合的底层源码使用的就是数组进行元素存储
于是使用remove()进行元素移除的话我们先看源代码
public E remove(int index) { rangeCheck(index); modCount++; E oldValue = elementData(index); int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // clear to let GC do its work return oldValue; }
首先E代表的是元素泛型,index代表的是我们要去除数组里面的元素索引
步骤:
1.首先remove方法调用的是rangeCheck()方法,该方法是判断index索引是否超出边界的,也就是你假设你数组只有7个元素,传一个index>=7肯定是会报错的,rangeCheck()方法如下
private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
2.某个变量modCount自加1,这个应该是类似计数器的东西,对实际结果无影响,不予理会
3.声明了一个变量numMoved,该变量的声明意思看第4步的第5个参数的解释即可
4.调用了System.arraycopy()方法,方法的五个参数分别代表的意思是
第一个参数是要被复制的数组
第二个参数是被复制的数字开始复制的下标
第三个参数是目标数组,也就是要把数据放进来的数组
第四个参数是从目标数组第几个下标开始放入数据
第五个参数表示从被复制的数组中拿几个数值放到目标数组中
对上述参数有一定理解之后,我们看源码的arraycopy方法,被复制的数组和目标数组竟然是同一个,也就是它其实是在自己的本身的数组上进行操作(数组创建后不可变,不能扩容)
于是我画了如下图进行演示,为了方便演示,画了三个数组,其实这是同一个数组,只不过是为了方便演示
5.最后,有一行elementData[--size] = null的代码,就是把上面数组的最后一个元素7赋值为null,让GC进行回收。因为数组本身是定长的(动态数组扩容用的是创建一个更大的新数组,而remove元素是在原来的数组上进行操作,只不过是数组原本存在元素的最后一位变成了null,因为被GC回收了。但其实没有remove之前,最后一位元素后面还可能有很多null,因为初始化arraylist容量就是10,你存3个,有7个null,remove一个,只不过多了一个null变成8个null而已)
GC进行回收的依据是,该对象因为不和数组有关联了,不再属于强引用对象,GCROOTS不能到达该对象,所以不久后GC就会回收这个对象
6.然后返回这个被删除的值
------------------------------------------------------------------综上,总结如下-------------------------------------------
ArrayList的remove()方法就是通过复制和清除的方式进行了功能完成,用通俗的语言进行解释一遍
remove()方法的作用就是:假设一个数组含有7个元素,我想删除索引为4的元素,那么从索引5开始的之后的元素我复制出来,然后按顺序依次赋值给本数组索引从4开始的元素,那么显而易见结果中的数组最后一个元素和倒数第二个元素是一样的,而且最后一个元素我们必须删除,因为size需要减1,逻辑基本就是这样
-------------------------------------------------------