一.简介
继承图
-List
--ArrayList
ArrayList 是一个由数组实现的列表,可以重复,不同步,可以存null;实现了List 的CURL 操作,且可以自动扩容.今天我们对该类的源码进行解析.
二.构造函数
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//其实就是以静态方法区的一个数组当成缓存,从而避免创建多个数组
三.CRUD 的操作
3.1 add 操作
/**
* Appends the specified element to the end of this list.
*翻译:增加一个特点的元素在list的最后
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 动态的堆内部的数组进行扩容
elementData[size++] = e;//把元素插在最后面
return true;
}
扩容
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//常规情况初始为10
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//mod 表示修改次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);//很明显,这里操作就是容量不足的时候,进行增加一个新的容器,并做复制操作
}
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
* 翻译: 增加数组的容积,确保 能存放所有的元素
* 具体的策略如下:
* 1.获得原容积的1.5倍的大小,与传进来的最小容量对比,选择比较小的
* 2.假如超过最大容量则用最大容量
* 3.然后做复制数据到新的容器
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
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);
}
小结:
- ArrayList 对象创建后,内部数组的初始长度未0,内部数组指向一个静态缓存数组
- 首次添加数据时,会扩容到10,或者自己指定的长度
- 每次扩容,都会扩大原来的1.5倍,或者自己指定的长度
- 每次扩容,实际都是新创建一个数组然后再把数据复制到新数组中然后返回
- 超过长度(Integer.MAX_VALUE - 8)就不会扩容了
- 最小指定的长度为负数,会抛异常
- size 表示的是逻辑容量而不是内部数组的实际容量
- modCount 代表修改的次数
3.1 get 操作
/**
* Returns the element at the specified position in this list.
* 翻译:返回指定位置(position)的元素
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
//检测index是否合法
private void rangeCheck(int index) {
if (index < 0 || index >= this.size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(int index) {
return (E) elementData[index];
}
3.2 set 操作:存放并返回对应的元素
“`java
public E set(int index, E element) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
“
3.2 remove 操作
“`java
/**
* Removes the element at the specified position in this list.
* Shifts any subsequent elements to the left (subtracts one from their
* indices).
*
* 翻译:移除列表中特定位置的元素,将任何后续元素向左移动(从他们中减去一个元素)
*/
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;
}
### 3.3 add &addAll
```java
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
// 注意:就算是增加多个元素 modCount 就 ++ 而已
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
<div class="se-preview-section-delimiter"></div>
3.4 clear
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
### 3.4 clear: 容积不变,元素清空,size置零
```java
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null;
size = 0;
}
<div class="se-preview-section-delimiter"></div>
四.SubList
ArrayList中,存在一个内部类SubList.他与ArrayList 一样继承AbstractList.同时有crud 操作
我们发现,parent就是对原始的list的引用,SubList 的crud 就是对ArrayList 的crud 操作
4.1.SubList的妙用
list.subList(100,200).clear();
### 四.SubList
ArrayList中,存在一个内部类SubList.他与ArrayList 一样继承AbstractList.同时有crud 操作
我们发现,parent就是对原始的list的引用,SubList 的crud 就是对ArrayList 的crud 操作
#### 4.1.SubList的妙用
list.subList(100,200).clear();
直接删除一段数据(100-199),而不是for循环,
其实就是迭代器删除的
protected void removeRange(int fromIndex, int toIndex) {
ListIterator it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i
#### 六.序列化
内部数组用transient 修饰,表示不被序列化,但是我们的数据都是放在数组中的,数据不序列化,我们持久化了有什么用呢?因为ElementData 不一定满的,没有用上的空间我们并不想再耗时间去序列化.但有存储数据的空间我们还是有序列化的,隐藏,java重写了writeObject 方法,以实现局部序列化
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
“`
七:总结
1.Arraylist 继承List,内部维护一个一维数组
2.使用1.5倍的方式扩容;
3.使用System.arraycopy()进行扩容的赋值
4.首次默认扩容10;
5.不同步,查询快,插入删除慢;
6.内部类SubList 最终调用也是ArrayList
7.ArrayList 重写了writeObject 方法优化数组的序列化