ArrayList的模拟实现(底层实现原理)
以下部分可能与实际写的方法名不同,但是基本需求还是一样的(添加,删除,插入,判断下标是否越界)
模拟实现ArrayList类(需求分析):
ArrayList属性:
存放int类型的数组 int[] arr;
实际添加元素的个数 int size;
ArrayList构造方法
无参构造方法 public ArrayList() {}
无参构造方法中,用于实例化arr数组,默认开辟10个空间
有参构造方法 public ArrayList(int count) {}
有参构造方法中,根据传入的count,创建指定空间的arr数组
补充:需要实现构造方法之间的调用
ArrayList成员方法
public void add(int value) {}
追加元素方法,把value存入数组arr中,注意考虑扩容的情况
扩容:size == arr.length,则需考虑扩容!
public int get(int index) {}
根据传入的索引,获取该元素索引对应的元素,注意判断index是否越界
public void insert(int index, int value) {}
在arr索引为index的位置,插入value元素,注意考虑扩容的情况和index是否越界
public void deleteElementWithIndex(int index) {}
根据索引index,删除arr数组指定位置的元素,注意判断index是否越界
public int deleteElementWithValue(int value) {}
根据value,找到value在数组arr中的索引,
如果该元素value存在,则删除该元素,并返回该元素所在的索引
如果该元素value不存在,则不对数组做任何操作,返回-1即可
代码如下:
Test01用来测试数据
public class Test01 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add(11);
list.add(22);
list.add(33);
list.add(44);
System.out.println(list.size());
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("-----------------");
ArrayList list1 = new ArrayList();
list1.add(1233);
list1.add(1234);
list1.add(1235);
list1.add(1236);
list1.add(1237);
list1.add(1238);
list1.remove(2);
list1.insert(2, 1235);
System.out.println(list1.size());
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
}
}
ArrayList用来实现基本功能
public class ArrayList {
/**
* 用于存放数据的数组
*/
private int[] elementData;
/**
* 用于保存实际存放元素的个数
*/
private int size;
/**
* 获取实际存元素的个数
* @return 返回实际存放元素的个数
*/
public int size() {
return this.size;
}
/**
* 无参构造方法
* 给elementData数组做初始化的工作,并且设置空间长度为10。
*/
public ArrayList() {
this(10);
}
/**
* 有参构造方法
* 给elementData数组做初始化的工作,并且设置指定的空间长度
* @param initialCapacity 数组的空间长度数值
*/
public ArrayList(int initialCapacity) {
if(initialCapacity < 0) { // 不合法
throw new RuntimeException("数组的空间长度不能为负数!" + initialCapacity);
}
else {
// 给elementData数组做初始化的工作,并且设置空间长度为initialCapacity
this.elementData = new int[initialCapacity];
}
}
/**
* 给容器添加数据
* @param element 添加的数据
*/
public void add(int element) {
// 1.判断数组是否扩容
ensureCapacityInternal(size + 5);
// 2.在数组末尾(size位置的地方)添加新的元素
elementData[size] = element;
// 3.实际存放元素个数递增
size++;
}
/**
* 根据索引获取数组中的元素
* @param index 索引值
* @return 返回index索引对应的数组元素
*/
public int get(int index) {
// 1.检查索引是否合法(明确:索引只需要获取实际存入的元素,默认值元素不需要!)
rangeCheck(index);
// 2.返回index索引对应数组中的元素
return elementData[index];
}
/**
* 在指定索引位置插入元素
* @param index 索引值
* @param element 需要插入的元素
*/
public void add(int index, int element) {
// 1.检查索引index是否合法(插入的元素可以在实际添加元素的末尾)
// elementData = {11, 22, 33, 0, 0};
if(index < 0 || index > size) {
System.out.println("索引越界异常!");
throw new IndexOutOfBoundsException("索引越界异常:" + index);
}
// 2.判断数组是否扩容
ensureCapacityInternal(size + 5);
// 3.把index之后的元素往后挪动一位(从后往前挪)
for(int i = size - 1; i >= index; i--) {
elementData[i + 1] = elementData[i];
}
// 4.把元素(element)插入到数组中的index位置
elementData[index] = element;
// 5.实际存放元素个数递增
size++;
}
/**
* 根据索引删除元素
* @param index 索引值
* @return 返回被删除的元素
*/
public int remove(int index) {
// 1.检查索引index是否合法
rangeCheck(index);
// 2.获取index对应的被删除元素值
int oldValue = elementData[index];
// 3.把删除元素索引(index)之后的元素往前挪动一位(从前往后挪)
// elementData = {11, 22, 33, 44, 0};
for(int i = index; i < size - 1; i++) {
elementData[i] = elementData[i + 1];
}
// 4.设置最后一个元素为默认值
elementData[size - 1] = 0;
// 5.实际存放元素个数递减
size--;
// 6.返回被删除的元素值
return oldValue;
}
/**
* 检查索引是否合法,合法索引区间:[0, size-1]
* @param index
*/
private void rangeCheck(int index) {
// elementData = {11, 22, 33, 0, 0};
if(index < 0 || index >= size) {
throw new IndexOutOfBoundsException("索引越界异常:" + index);
}
}
/**
* 实现给数组扩容操作
* @param capacity 扩容之后数组的空间长度
*/
private void ensureCapacityInternal(int capacity) {
// 1.1当数组实际存放元素的个数和数组的空间长度相等时,这时需要扩容
if (size == elementData.length) {
// 1.2创建一个空间长度更大的数组
int[] newArr = new int[capacity];
// 1.3把原数组(elementData)中的元素拷贝到新数组newArr中
System.arraycopy(elementData, 0, newArr, 0, size);
// 1.4让原数组(elementData)指向新创建出来的数组(newArr)
elementData = newArr;
}
}
}