JDK8中List的remove()步骤源码分析
怎么使用for循环一条条删除List中的数据?如果面试者对List中remove底层实现方法不了解的话很容易给出错误的答案:remove(index)。
原理解析见最后说明,正确实现方法如下:
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List<String> obj = new ArrayList<String>();
obj.add("A");
obj.add("B");
obj.add("C");
obj.add("D");
obj.add("E");
obj.add("F");
obj.add("G");
int size = obj.size() - 1;
方法一:
for (int i = 0; i < size; i++) {
System.out.println(obj.remove(0));
}
方法二:
for (int i = size - 1; i >= 0; i--) {
System.out.println(obj.remove(i));
}
System.out.println(obj.size());
}
}
查看JDK8中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;
}
由源码可以看出ArrayList的内部有维护数组elementData和变量size用来对List中的数据进行操作。每删除一次数据后List的结构会进行一次修改,此时对应的elementData中的数据会被删除,对应的数组下标也会进行删除且剩下的数据的下标也会进行对应的修改。
源码解析如下:
private int size;
源码解释为:The size of the ArrayList (the number of elements it contains)。
rangeCheck(index)
查看传入索引的范围是否为index>=size,如果是则抛出索引越界异常。
protected transient int modCount = 0;
源码解释为:The number of times this list has been structurally modified。
什么是结构变化请参考:http://ericchunli.iteye.com/blog/2356721
System.arraycopy()
系统提供的数组浅拷贝的方法,此处用来修改elementData数组中的元素。
什么是浅拷贝请参考:http://ericchunli.iteye.com/blog/2360546
transient Object[] elementData;
用来处理List的数组的底层数据结构。
源码解释为:The array buffer into which the elements of the ArrayList are stored。The capacity of the ArrayList is the length of this array buffer。Any empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA will be expanded to DEFAULT_CAPACITY when the first element is added。
private static final Object[] EMPTY_ELEMENTDATA = {};
源码解释为:Shared empty array instance used for empty instances。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
源码解释为:Shared empty array instance used for default sized empty instances. We distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when first element is added。
Java关键字transient概述
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。Java的序列化提供了一种持久化对象实例的机制。当持久化对象时可能有一个特殊的对象数据成员,如果不想用序列化机制来保存它,为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。
关于Java的序列化和反序列化会在接下来的内容中详细描述。