037:Arraylist集合源码深度解析
1 Arraylist集合课程基本的介绍
课程内容:
1.Java8中Arraylist与Vector集合区别
2.Java8中ArraylistAdd方法数组如何实现扩容
3.Java8中ArraylistRemove方法源码分析
4.Java8中完全手写Java8 Arraylist框架
2 Arraylist集合构造函数源码分析
基本原理思想:
Arraylist集合底层使用动态数组(object类型)实现,随机查询效率非常快,插入和删除需要移动整个数组、效率低。
ArrayList不是线程安全的集合; Vector是线程安全的集合。
3 Arraylist集合框架底层数组扩容原理
public class ListTest001 {
public static void main(String[] args) {
Object[] elementData = {"1", "2", "3"};
System.out.println("数组扩容前:");
for (Object e : elementData) {
System.out.println("elementData:" + e);
}
int newCapacity = 10;
// 对原数组实现扩容,将旧的数组数据复制到新的数组中,返回新的数组,容量为newCapacity
Object[] objects = Arrays.copyOf(elementData, newCapacity);
System.out.println("数组扩容后:");
for (Object o : objects) {
System.out.println("objects:" + o);
}
}
}
运行结果:
4 Arraylist集合框架数组扩容
Arraylist数组扩容分析
- 第一次添加数据的时候,数组默认扩容是为10;
- int newCapacity = oldCapacity + (oldCapacity >> 1);
oldCapacity=10;
int newCapacity = oldCapacity + oldCapacity/2;
newCapacity=15
新数组容量是原数组容量的1.5倍
数组的最大容量:Integer的最大值2^32
System.arraycopy(src, srcPos, dest, destPos, length);
src 原数组 srcPost 起始位置 dest目标数组 destPos 目标数组放置的起始位置 length 复制长度
5 手写简单版本ArrayList实现基本功能
public interface MayiktList<E> {
/**
* 集合大小
* @return
*/
int size();
/**
* 添加元素
* @param e
* @return
*/
boolean add(E e);
/**
* 使用下标查询元素
* @param index
* @return
*/
E get(int index);
/**
* 使用下标删除元素
* @param index
* @return
*/
public E remove(int index);
}
public class MayiktArrayList<E> implements MayiktList<E> {
/**
* elememtData数组存放ArrayList所有数据,transient作用不能被序列化
*/
transient Object[] elementData;
/**
* 给数组容量赋值为空
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 数组初始容量默认为0
*/
private int size;
/**
* 数组默认容量大小为10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 2^32-8
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
public MayiktArrayList() {
elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
@Override
public int size() {
return size;
}
@Override
public boolean add(E e) {
// 对数组实现扩容
ensureCapacityInternal(size + 1);
// 对数组元素赋值
elementData[size++] = e;
return true;
}
@Override
public E get(int index) {
return (E) elementData[index];
}
@Override
public E remove(int index) {
// 检查下标位置是否越界
rangeCheck(index);
// 获取要删除的对象
E oldValue = get(index);
// 计算移动的位置
int numMoved = size - index - 1;
// 判断删除的数据不是最后一个,将删除数据后面的数据往前移动一位
if (numMoved > 0) {
System.arraycopy(elementData, index + 1, elementData, index, numMoved);
}
// 如果numMoved为0的情况下,后面不需要往前移动,直接将最后一条数据赋值为null
elementData[--size]= null;// clear to let GC do its work
return null;
}
public void rangeCheck(int index) {
if (index > size) {
throw new IndexOutOfBoundsException("数组越界,下标位置index:" + index);
}
}
private void ensureCapacityInternal(int minCapacity) {
// 添加元素的时候,如果数组为空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
// 第一次 10-0>0
if (minCapacity - elementData.length > 0) {
// 对数组实现扩容
grow(minCapacity);
}
}
private void grow(int minCapacity) {
// 获取数组长度
int oldCapacity = elementData.length;
// 新容量=原来容量+原来容量一半
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 第一次:0-10<0 第一次对数组容量初始化操作
if (newCapacity - minCapacity < 0) {
// 新容量=10
newCapacity = minCapacity;
}
if (newCapacity - MAX_ARRAY_SIZE > 0) {
newCapacity = hugeCapacity(minCapacity);
}
// 开始对数组实现扩容,将旧的数组数据复制到新的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
/**
* 判断最小初始化容量,限制数组扩容最大值
*
* @param minCapacity
* @return
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
}
public class ListTest {
public static void main(String[] args) {
MayiktArrayList<String> stringMayiktArrayList = new MayiktArrayList<String>();
for (int i = 0; i < 10; i++) {
stringMayiktArrayList.add("蚂蚁课堂" + i);
}
stringMayiktArrayList.add("蚂蚁课堂11");
System.out.println("删除数据之前:");
for (int i = 0; i < stringMayiktArrayList.size(); i++) {
System.out.println(stringMayiktArrayList.get(i));
}
stringMayiktArrayList.remove(2);
System.out.println("==============");
System.out.println("删除数据之后:");
for (int i = 0; i < stringMayiktArrayList.size(); i++) {
System.out.println(stringMayiktArrayList.get(i));
}
}
}
运行结果: