背景
现在看 一个简单的main函数,直接上代码
public class ArrayList{
public static void main(String[] args){
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
list.add("g");
list.add("h");
list.add("i");
list.add("j");
//往集合中添加第11个元素
list.add("k");
//集合中获取指定位置元素
Object o1= list.get(0);
System.out.println(o1);
}
}
对main函数进行简单分析
先看ArrayList这个类里的成员变量
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] 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.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 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.
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
构造方法处打个断点,然后debug启动,构造里面走了这个方法,这个常量是一个空Object数组,赋值给了成员属性elementData,它也是一个Object数组,构造方法里就是做了这个事情。说明ArrayList底层用的是一个Object数组。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
debug进入源码
添加list.add(“a”);
进入源码
public boolean add(E e) {
//size是0,0+1=1 是入参
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
查看ensureCapacityInteranl方法
private void ensureCapacityInternal(int minCapacity) {
//初始化的时候,已经把这个常量赋值给了这个elementData,所以他们两个是相等的
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//取这两个值的最大值,默认容量这个值是10,10和1比较,10大的,取10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
接着进入ensureExplicitCapactiy()方法中
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//传进来的是10,elementData是一个空的数组,所以length是0,也就是10-0。第一次扩容后数组长度是10,所以在小于10个元素添加的时候,此处都是小于0,所以就不会走扩容,当minCapacity大于11的时候,此处就大于0,走扩容grow方法。
if (minCapacity - elementData.length > 0)
//扩容方法,第一给数组的容量是10个。以后每次扩容都是数组容量的1.5倍数,数组容量+数组容量/2
grow(minCapacity);
}
进入grow方法
private void grow(int minCapacity) {
// 此刻length是0,
int oldCapacity = elementData.length;
//新的容量=老的容量向右移动一位,这块就是通常所说的扩容1.5倍的原理,这个是newCapacity也是0
//oldCapacity>>1 等于oldCapacity/2,右移几位就是除以2的几次方
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 0 减去传进来的10 小于0
if (newCapacity - minCapacity < 0)
//然后把10赋值给newCapacity,新数组容量是10,//如果初始的时候,我们不设定,这个容量就是10。开辟一块长度为10的数组。
newCapacity = minCapacity;
///10-最大数组长度2147483639,不大于0,所以不会走下面这个方法。
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//有了这个长度是10的数组,我们需要把原来数组元素copy到新的数组当中
elementData = Arrays.copyOf(elementData, newCapacity);
}
最后回到add方法
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
//添加第一个元素成功,然后size值加1,从0变为1。
elementData[size++] = e;
return true;
}
第一个元素a 添加成功了。接下来一直添加是一样的,小于10个元素的时候是不需要扩容的 。但是加到第十一个的时候,变了。当数组添加元素超过10个的时候,这时候就要扩容,扩容的大小是容量大小的1.5倍。然后把老数组的元素copy到新数组里。
以上就是添加元素的源码分析。
下面再说下,获取元素的源码。进入get方法中
public E get(int index) {
//先判断索引是否在长度范围内
rangeCheck(index);
return elementData(index);
}
进入rangeCheck方法,如果索引值大于数组长度,就会抛出异常数组角标越界
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
如果没有越界,进入elementData方法中,根据下标直接取元素,并返回。
E elementData(int index) {
return (E) elementData[index];
}
以上就是ArrayList的源码分析,总结下就是,第一次扩容给数组长度10,然后添加元素个数小于10,不会扩容个,当添加元素个数大于10的时候,就会扩容,扩容是数组长度的1.5倍。获取是直接根据角标获取,先判断下角标是否在数组长度范围内,超过长度范围内,就抛出角标越界,在范围内,就根据下标,直接去取元素。
写在最后
ArrayList数据结构,相信每个开发人员都用到过,但是真正领会其中含义,看过或分析过源代码的肯定不多。
想了解更多知识,请关注我吧_