JAVA——底层源码阅读——集合ArrayList的实现底层源码分析
Posted 叶不修233
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA——底层源码阅读——集合ArrayList的实现底层源码分析相关的知识,希望对你有一定的参考价值。
JAVA——底层源码阅读——集合ArrayList的实现底层源码分析
- 当前 jdk版本:jdk1.8.0_74
一、提出问题
集合ArrayList的底层原理是什么,它的增删改查是怎么实现的,为什么它的长度是可变的?
二、查看ArrayList源码
步骤1、新建java文件,把代码敲上去如下
public class Test
public static void main(String[] args)
ArrayList arrayList = new ArrayList();
arrayList.add("hello");
arrayList.add("world");
arrayList.remove(0);
arrayList.set(0, "世界");
arrayList.get(0);
System.out.println(arrayList);
步骤2、查看源码。
如何查看之前文章中已有详细步骤,不再赘述,以下直接展示具体源码。
1、增add()
2、删remove()
3、改set()
4、查get()
步骤3、阅读和分析源码。
1、增add()
如下所示,add()方法中一共有三行代码:
第一行是调用了ensureCapacityInternal方法;
第二行是往数组elementData的第size++位置下标增加值e;
第三行是返回一个true;
public boolean add(E e)
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
由第二行可知,集合ArrayList的底层原理是依赖于数组Array的,接下来从第一行开始分析代码的实现过程。
(1)点击跳转到ensureCapacityInternal()方法中,如图所示:
(2)点击跳转查看if判断条件里的数组elementData和常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA如图所示:
可知,这个条件的意思是:如果数组elementData为空,就执行下面一行代码
(3)点击跳转查看if判断中的执行代码minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);如图所示:
意为,调用Math.max()方法,取常量DEFAULT_CAPACITY和变量minCapacity中的最大值赋给参数minCapacity。
跳转查看常量DEFAULT_CAPACITY的值为10。
(4)回到ensureCapacityInternal()方法,查看if判断之外的这行代码,即,无论有没有进入if判断,这行代码都将被执行。这行代码的意思的,把上面的minCapacity作为入参传递过来,调用 ensureExplicitCapacity(minCapacity)方法。
(5)点击跳转查看 ensureExplicitCapacity(minCapacity)方法,如图所示:
意为:如果传入参数minCapacity>数组elementData的长度,就把minCapacity参数继续传递下去,调用grow(minCapacity)方法
(6)点击跳转查看grow(minCapacity)方法,如图所示:
意为:复制一个elementData数组,新数组长度=旧数组长度*1.5
至此,我们可以发现集合ArrayList长度可变的核心代码实现:基于数组的copyOf方法
(7)总结:
集合ArrayList的add()方法:本质上是依赖于数组Array。
在创建集合时,会定义一个初始长度为10的数组,在10之内的add()方法调用数组的给指定下标元素赋值方法;
当集合元素继续增加,到长度超过10时,会调用数组的copyOf方法对数组进行1.5倍的长度扩容。
2、删remove()
删除方法比较简单,大致与数组操作一致,如图,不再分步骤分析
3、改set()
4、查get()
三、尝试自定义ArrayList
新建一个java文件,任意命名,模仿以上分析的ArrayList实现步骤去重写一个简略版的ArrayList
因为上面已经分析过核心代码的作用,不再重复按点赘述。
整个类的代码及注释如下:
代码
import java.util.Arrays;
/**
* @description: ArrayList底层源码分析
* @author: z
* @date: 2022年4月26日
*/
public class YebuxiuArrayList
//声明一个类型为Object的数组
Object[] elementData;
//定义一个私有的常量,类型为Object[],长度为0的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;
//声明一个类型为int的变量size,用于记录数组中元素个数,初始值未赋值则默认为0
private int size;
//声明一个类型为int的常量,用来记录数组的默认长度,初始值赋值为10
private static final int DEFAULT_CAPACITY = 10;
/**
* 构造方法-ArrayList的创建
*/
public YebuxiuArrayList()
//给声明的数组赋值,长度为0
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
/**
* add()方法-向ArrayList中插入数据
*/
public boolean add(Object obj)
//调用这个方法
ensureCapacityInternal(size + 1);
//往数组中下标为size的位置插入元素obj,然后给size+1
elementData[size++] = obj;
return true;
/**
* ArrayList的长度初始化,初始化长度默认为10
*/
public void ensureCapacityInternal(int minCapacity)
//判断:如果数组为空,就给minCapacity赋值为10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
//调用这个方法
ensureExplicitCapacity(minCapacity);
/**
* ArrayList的长度发生变化时,调用grow()方法
*/
private void ensureExplicitCapacity(int minCapacity)
grow(minCapacity);
/**
* 如果ArrayList变化后的长度小于10,长度就不变
* 如果ArrayList变化后的长度大于10,就按1.5倍对ArrayList的长度进行扩容
*/
private void grow(int minCapacity)
//定义变量记录当前数组长度
int oldCapacity = elementData.length;
//定义变量记录新数组长度
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// if (newCapacity - MAX_ARRAY_SIZE > 0)//MAX_ARRAY_SIZE=2147483639 [0x7ffffff7]
// newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//使用数组的copyOf方法,复制一个新数组,名字不变,长度为新数组长度
elementData = Arrays.copyOf(elementData, newCapacity);
/**
* 获取对应下标位置的元素
*/
public Object get(int index)
return elementData(index);
public Object elementData(int index)
return elementData[index];
/**
* 移除指定下标的元素
* 并让该下标之后的元素下标往前进一位
*/
public Object remove(int index)
rangeCheck(index);
Object 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的长度
* 就抛出定义好的异常
*/
private void rangeCheck(int index)
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
/**
* 定义的异常返回值
*/
private String outOfBoundsMsg(int index)
return "Index: "+index+", Size: "+size;
/**
* 将指定下标位置设置为指定元素(增和改语法一致)
*/
public Object set(int index, Object element)
rangeCheck(index);
Object oldValue = elementData(index);
elementData[index] = element;
return oldValue;
/**
* 重写toString()方法
* 直接输出ArrayList,输入里面的元素,而不是内存地址
*/
@Override
public String toString()
StringBuilder sb = new StringBuilder();
sb.append("[");
for(int i = 0;i<elementData.length;i++)
if(elementData[i]!=null)
sb.append(elementData[i]).append(",");
String s = sb.substring(0, sb.length()-1);
s = s +"]";
return s;
运行结果
测试使用自定义的YebuxiuArrayList创建对象和实现增删改查如图所示,均没有问题
以上是关于JAVA——底层源码阅读——集合ArrayList的实现底层源码分析的主要内容,如果未能解决你的问题,请参考以下文章