由于自己看源码时感觉难以看懂,即便看懂,隔一段时间回顾时也经常蒙圈,所以手写源码中的部分,达到模拟的目的,便于理解。
1、简介
ArrayList的数据结构是数组列表,下面将通过代码,模拟并介绍这种数据结构的特点。
2、模拟ArrayList的类名
public class ArrayListTest<E>
3、模拟ArrayList的成员变量
/**
* 数组列表大小
*/
private int size;
/**
* 数组列表,初始化为10个长度
*/
private Object[] elementData = new Object[10];
4、模拟ArrayList的add方法
/**
* 给数组列表添加元素
*
* @param e 元素
* @return
*/
public boolean add(E e) {
// 检查并调整大小:若即将溢出,则扩大原来的一半大小
this.resize();
// 添加元素至数组内,且数组下标+1
elementData[size++] = e;
return true;
}
/**
* 检查并调整大小:若即将溢出,则扩大原来的一半大小
*/
private void resize() {
// 原数组的数据长度
int oldCapacity = elementData.length;
// 若即将溢出,则扩大原来的一半大小
if (size + 1 > oldCapacity) {
System.out.println("oldCapacity=" + oldCapacity);
// 新数组的数据长度
int newCapacity = oldCapacity + oldCapacity / 2;
System.out.println("newCapacity=" + newCapacity);
// 原数组拷贝数据至新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
5、模拟ArrayList的get方法
/**
* 从数组列表中查询元素
*
* @param index 查询元素的下标
* @return
*/
public E get(int index) {
// 校验下标是否合理
if (index < 0 || index >= size) {
return null;
}
// 根据数组下标返回数组元素
return (E) elementData[index];
}
6、模拟ArrayList使用add、get方法
public static void main(String[] args) {
ArrayListTest<String> arrayListTest = new ArrayListTest<>();
arrayListTest.add("1");
arrayListTest.add("2");
arrayListTest.add("3");
arrayListTest.add("4");
arrayListTest.add("5");
arrayListTest.add("6");
arrayListTest.add("7");
arrayListTest.add("8");
arrayListTest.add("9");
arrayListTest.add("10");
arrayListTest.add("11");
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arrayListTest.size; i++) {
sb.append(arrayListTest.get(i)).append(",");
}
sb.delete(sb.length() - 1, sb.length()).append("]");
System.out.println(sb);
}
控制台输出:
oldCapacity=10
newCapacity=15
[1,2,3,4,5,6,7,8,9,10,11]
从中可以看出ArrayList的特点:数据放数组中存储,有长度限制,需要分配连续的内存空间,添加元素时可能导致数据扩容,数组扩容的开销大,访问元素的开销小。
7、附上完整代码
import java.util.Arrays;
/**
* 模拟数组列表
*
* @author pengxin
* @date 2022/1/13 14:46
*/
public class ArrayListTest<E> {
/**
* 数组列表大小
*/
private int size;
/**
* 数组列表,初始化为10个长度
*/
private Object[] elementData = new Object[10];
/**
* 给数组列表添加元素
*
* @param e 元素
* @return
*/
public boolean add(E e) {
// 检查并调整大小:若即将溢出,则扩大原来的一半大小
this.resize();
// 添加元素至数组内,且数组下标+1
elementData[size++] = e;
return true;
}
/**
* 检查并调整大小:若即将溢出,则扩大原来的一半大小
*/
private void resize() {
// 原数组的数据长度
int oldCapacity = elementData.length;
// 若即将溢出,则扩大原来的一半大小
if (size + 1 > oldCapacity) {
System.out.println("oldCapacity=" + oldCapacity);
// 新数组的数据长度
int newCapacity = oldCapacity + oldCapacity / 2;
System.out.println("newCapacity=" + newCapacity);
// 原数组拷贝数据至新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
/**
* 从数组列表中查询元素
*
* @param index 查询元素的下标
* @return
*/
public E get(int index) {
// 校验下标是否合理
if (index < 0 || index >= size) {
return null;
}
// 根据数组下标返回数组元素
return (E) elementData[index];
}
public static void main(String[] args) {
ArrayListTest<String> arrayListTest = new ArrayListTest<>();
arrayListTest.add("1");
arrayListTest.add("2");
arrayListTest.add("3");
arrayListTest.add("4");
arrayListTest.add("5");
arrayListTest.add("6");
arrayListTest.add("7");
arrayListTest.add("8");
arrayListTest.add("9");
arrayListTest.add("10");
arrayListTest.add("11");
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < arrayListTest.size; i++) {
sb.append(arrayListTest.get(i)).append(",");
}
sb.delete(sb.length() - 1, sb.length()).append("]");
System.out.println(sb);
}
}