ArrayList是JDK中的一个基于数组实现的线性的可变长度的集合类,而且实现了List接口。数组
//建立ArrayList
ArrayList list = new ArrayList();
复制代码
建立完成后,点击进入ArrayList源码,能够发现是bash
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
复制代码
这样的一个无参构造方法对ArrayList
进行了初始化操做,其中elementData
是一个Object
类型的数组,DEFAULTCAPACITY_EMPTY_ELEMENTDATA
也是一个Object
类型的数组且长度为0。函数
//建立ArrayList
ArrayList list = new ArrayList(20);
复制代码
再次点击就会发现会调用一个制定了初始化容量的构造方法ui
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
复制代码
根据代码可知,咱们传入参数后会建立一个容量为20
的数组。若是传入的不是20
而是0
的话,就会建立一个容量为空的数组,也就是this.elementData = {}
。this
//建立ArrayList
ArrayList list = new ArrayList();
list.add("aaa");
复制代码
点击进入以后能够发现以下代码spa
public boolean add(E e) {
//用于检测容量是否够用
ensureCapacityInternal(size + 1); // Increments modCount!!
//将元素添加进集合中,而且维护size的值。 size的初始值为0
elementData[size++] = e;
return true;
}
复制代码
点击ensureCapacityInternal(size + 1);
会发现以下代码code
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
复制代码
从代码中能够看出传入的是添加元素须要的最小空间,而后再点击calculateCapacity
方法对象
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//DEFAULT_CAPACITY = 10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
复制代码
发现传入的是一个Object
类型的数组和须要的最小容量。由于elementData
是空的,因此会进入第一个if
判断,这样会从10和0
之间选取最大值,结果显而易见,因此10被返回到ensureExplicitCapacity
的参数列表中。索引
接着再点击ensureExplicitCapacity
。接口
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//扩容函数
grow(minCapacity);
}
复制代码
从这里能够看出会将刚才传入的10传到扩容的函数中,再点击grow
private void grow(int minCapacity) { //minCapacity = 10
//elementData是一个空数组,因此oldCapacity为0
int oldCapacity = elementData.length;
// newCapacity = 0 + 0 因此newCapacity = 0
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 0 - 10 < 0 true
if (newCapacity - minCapacity < 0)
// newCapacity = 10
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
复制代码
从中得出newCapacity = 10
,而后调用copyOf
方法进行复制,复制完成就会将elementData
的长度设置为10。
总结:在第一次调用add()方法时,会将容量初始化为10,可是若是老是执行添加操做,就会再次到达ArrayList的扩容标准
//建立ArrayList
ArrayList list = new ArrayList();
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa");
list.add("aaa"); //第11次调用add()方法
复制代码
此时咱们再执行上面的操做,直到这里
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 11 - 10 > 0 true
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
复制代码
再次执行扩容操做
private void grow(int minCapacity) { //minCapacity = 11
// oldCapacity = 10
int oldCapacity = elementData.length;
//newCapacity = 10 + 10 / 2 15
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 15 - 11 < 0 false
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 进行copy
elementData = Arrays.copyOf(elementData, newCapacity);
}
复制代码
当拷贝完成扩容操做执行完毕,elememtData
的容量此时为15
System.out.println(list.get(2));
复制代码
get
方法须要传入数组下标,并经过下标返回数组中的值。点击get
方法会显示以下内容
public E get(int index) {
//检查下标合法性,不合法则抛出异常
rangeCheck(index);
//直接返回数组中下标为index的元素
return elementData(index);
}
复制代码
list.set(2, "bbb");
复制代码
这里表示想将数组中下标为2的元素设置为bbb
。点击进入
public E set(int index, E element) {
//检查下标合法性
rangeCheck(index);
//保存索引为index位置的值
E oldValue = elementData(index);
//将传入的元素设置在index位置
elementData[index] = element;
//返回保存的元素
return oldValue;
}
复制代码
经过传入index和E
类型的元素,更新完成后将原来的元素值返回。
System.out.println(list.remove(2));
复制代码
删除下标为2的元素,并将删除前的元素返回,点击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
ArrayList list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
//建立迭代器
Iterator it = list.iterator();
//判断迭代器中是否还有下一个元素
while (it.hasNext()){
//将对象取出
Object o = it.next();
System.out.println(o);
}
复制代码
迭代器能够遍历ArrayList
中的元素,点击iterator()
public Iterator<E> iterator() {
return new Itr();
}
复制代码
在迭代器内部建立了一个Itr
对象,再点击
//指向元素的游标,当前cursor = 0
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
//迭代器中是否包含下一个元素
public boolean hasNext() {
return cursor != size;
}
//将游标向后移动
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
//将cursor向后移动
cursor = i + 1;
return (E) elementData[lastRet = i];
}
复制代码
进入以后关注以上方法及参数 由于上面添加了3个元素,因此size
为3,cursor
与size
不相等,返回true
,因此会进入while
循环并执行next
方法,首先会将cursor
赋值给i,此时i为0,而后cursor向后移动最后将下标为0的元素返回。一直循环下去直至hasNext
返回false
。