我在阅读源码的过程中很多时候是没有头绪的。所以为了避免大家也遇到这种状况,源码不求全求大,做到“透过实践看源码”,分块分层。
首先对ArrayList做个总体介绍:
ArrayList的底层存储结构是数组,实际上在这个类中真正保存数据的是内部定义的一个数组,自身的数据操作只是封装了数组的操作!
- 首先看定义:
//创建ArrayList对象;<String>泛型,表明list将来保存的是String
ArrayList<String> list=new ArrayList<String>();
创建实例首先看内部变量
/**
* 默认的集合容量:10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空的数组实例(共享),用来在指定容量为0时初始化。
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 空的数组实例(共享)。在默认的构造函数中初始化
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 底层结构,数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 集合大小,指的是集合内包含的元素个数
*/
private int size;
然后调用默认构造函数
/**
* 默认的构造函数;Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
至此就完成了实例化操作,此时ArrayList对象list,内部elementData 指向了一个Object[0]数组,size默认值为0。
随后的操作均是对数组elementData 进行操作。
- 添加数据
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<String>();
list.add("first");
list.add("second");
}
源码分析
//添加数据
public boolean add(E e) {
//扩充集合容量,防止溢出,直至添加第10个数据时都不会再扩充容量,避免频繁扩充容量导致性能下降
ensureCapacityInternal(size + 1);
//添加数据
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
//使用默认构造函数实例化,第一次添加数据minCapacity=10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//比较DEFAULT_CAPACITY, minCapacity的最大值,赋值给minCapacity
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 如果minCapacity较大,扩充容量
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 集合的最大容量
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 扩充容量
*/
private void grow(int minCapacity) {
// 原来的集合容量
int oldCapacity = elementData.length;
//>>1相当于除于2取整,构建新容量
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//复制一个新的数组,容量为newCapacity,内容为elementData,多余的用默认值填充,如null,0;
elementData = Arrays.copyOf(elementData, newCapacity);
}
- 获取元素
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<String>();
list.add("first");
list.add("second");
//第一个元素值
String ele1=list.get(0);
System.out.println(ele1);
//第二个元素值
String ele2=list.get(1);
System.out.println(ele2);
}
输出结果: first
second
源码分析
/**
* 返回索引元素
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
/**
* 检查索引是否超出范围,超出就报异常
*/
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
// 根据索引获取元素。底层是数组。
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
至此ArrayList类的基本 添加数据,获取数据 的源码解析完毕!
继续阅读……
如有错误,欢迎指正!!!