先看例子

比如我们要把“周八”这个人从数组中删除,如图:

我们只能循环数组,找到“周八“的下标5,由于数组没有提供删除方法,我们只能把下标为5的位置赋值为null(造成了数组空洞),“周八”这个Person对象已经没有引用指向它了,JVM的垃圾回收机制会在适当的时候回收它。但数组的长度还是10。下次当我们再循环查找某人时,稍不注意就会报空指针异常,虽然我们可以写非空去判断,但还是不太友好,我们把null后面的所有元素引用复制一下,往前拷贝一份,把null这个空给填上,如下图

复制后:

null之后的ref引用都按顺序复制了一份到原来的null的位置,原有的1引用被覆盖,但perArr[9]里的引用的指向还是不变(注意,是复制不是挪动,仔细看一下上面两个图)。
注意:perArr[8],perArr[9]指向的是同一个对象,这显然不是我们所要的结果,再处理一下,我们把perArr[9]的引用赋值为null。如下图:

问题似乎解决了,但数组长度还是10,还需要自行维护了一个size来记录长度,以上数组复制的代码,我们都要自己去写,好在ArrayList这个类已经实现了,数组拷贝工作交给它就好,我们只需要调用ArrayList这个类提供的remove删除元素就行,至于底层数组怎么拷贝,元素怎么删除由ArrayList对象本身去搞定(面向对象的思想)

原理:

如果删除第i的元素,第i个位置的元素变为null,后边的元素复制一份,依次从第i个位置进行赋值,因为是复制而不是移动,这时倒数第二个位置的元素最后一个位置的元素都是最后一个位置的对象引用,我们需要把最后一个位置的元素置为null。

当我们用下标方式去删除元素时,如果删除的是最后一个元素,不会触发数组底层的复制,时间复杂度为O(1)。如果删除第i的元素,会触发底层数组复制n-i次,根据最坏情况,时间复杂度为O(n)。

参考链接:https://mp.weixin.qq.com/s?src=11&timestamp=1630308020&ver=3283&signature=ozf5ZpBd5D5vv12M6j0NIx5Ev5x7mtnTP3vZuhwSrSk***xzHxPDPmX3xtMlrmKsK5IShUFUsPCmFHmIsRO0c3vQVPsSR7DctaB4gYDt1XjqxOeeV-xtofENdCYSIPzN&new=1