學習數據結構 -動態數組 模仿 ArrayList
public class ArrayList<E> {
/**
* 大小
*/
private int size;
/**
* 原始數組
*/
private Object[] elementData;
/**
* 空數組
*/
private static final Object[] EMPTY_DATA = {};
/**
* 默認數組長度
*/
private static final int DEFAULT_CAPACITY = 10;
public ArrayList(int initialCapacity) {
// 大於0 設置爲用戶大小 等於0 給空數組 否則設置錯誤
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_DATA;
} else {
throw new IllegalArgumentException("長度設置錯誤" + initialCapacity);
}
}
public ArrayList() {
// 沒設置給個空數組
this.elementData = EMPTY_DATA;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
/**
* 添加數據
*
* @param e 數據
* @return 添加成功
*/
public boolean add(Object e) {
// 確保我的數組長度是當前實際大小+1
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
/**
* 添加方法 帶下標位置
*
* @param index 下標
* @param e 數據
* @return 添加成功
*/
public boolean add(int index, Object e) {
// 校驗位置
rangeCheckForAdd(index);
// 確保數組長度我能放進去
ensureCapacityInternal(size + 1);
//添加指定位置並移動指定位置後數據 系統方法 複製數組很有趣 可以實現自己複製給自己
// 比如 0 1 2 3 4 5 我插入下標爲3 的數據 變成 0 1 2 e 3 4 5 意思就是 把源數組 下標爲3起始位置 開始 copy 到目標數組index+1 起始位置後的數據
// copy長度size-index
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = e;
size++;
return true;
}
/**
* 獲取指定下標數據
*
* @param index 下標
* @return 數據
*/
public E get(int index) {
// 驗證下標是否在正常範圍
rangeCheck(index);
return (E) elementData[index];
}
/**
* 設置 指定下標數據
*
* @param index 下標
* @param e 修改數據
*/
public E set(int index, int e) {
// 驗證下標是否在正常範圍
rangeCheck(index);
// 返回舊值
E oldElementData = (E) elementData[index];
elementData[index] = e;
return oldElementData;
}
/**
* 刪除指定下標數據
*
* @param index 下標
* @return 舊數據
*/
public E remove(int index) {
// 檢測下標是否越界
rangeCheck(index);
//返回舊值
E oldElementData = (E) elementData[index];
// 上面index能過檢測 最大的大小就是size -1 就是數組最後一個值的下標
int move = size - index - 1;
if (move > 0) {
// 說明需要移動下標 不是最後一位 比如 我有 1,2,3,4 數組 我要修改 數組爲2下標的數據 我就要移動4 移動到 3 的位置 長度爲 size-2-1
System.arraycopy(elementData, index + 1, elementData, index, move);
}
// 移動過後最後一位需要清空 不然數據不會消失
elementData[--size] = null;
return oldElementData;
}
/**
* 返回數據指定下標
*
* @param e 數據
* @return 下標
*/
public int indexOf(Object e) {
if (e != null) {
for (int i = 0; i < size; i++) {
if (e.equals(elementData[i])) {
return i;
}
}
} else {
return -1;
}
return -1;
}
@Override
public String toString() {
StringJoiner stringJoiner = new StringJoiner(", ", "[", "]");
for (Object element : elementData) {
if (element != null) {
stringJoiner.add(String.valueOf(element));
}
}
return stringJoiner.toString();
}
/**
* 下標長度位置是否合法判斷 添加
*
* @param index 下標
*/
private void rangeCheckForAdd(int index) {
// 只能添加下邊小於等於 當前list長度的 可以添加等於size下標位置的數據
if (index > size || index < 0) {
throw new IndexOutOfBoundsException("index 越界(添加時)" + index);
}
}
/**
* 驗證下標是否越界 獲取
*
* @param index 下標
*/
private void rangeCheck(int index) {
// 獲取僅存在的下標
if (index >= size) {
throw new IndexOutOfBoundsException("下標越界異常" + index);
}
}
/**
* 確保容量有多大
*
* @param minLength 最小長度
*/
private void ensureCapacityInternal(int minLength) {
// 判斷 大小 給予 默認大小
if (elementData == EMPTY_DATA) {
//表示是空數組給個默認長度
minLength = DEFAULT_CAPACITY;
}
// 如果 數組長度 已經小於我們需要的最小長度 就擴容
if (minLength > elementData.length) {
// 舊長度
int oldLength = elementData.length;
// 新長度等於舊長度 的 1.5倍 舊長度+舊長度*0.5
int newLength = oldLength + (oldLength >> 1);
Object[] copy = new Object[newLength];
// 把舊數組 賦值給新數組
System.arraycopy(elementData, 0, copy, 0,
oldLength);
log.warn("擴容原始長度{},擴容後長度{}", oldLength, newLength);
elementData = copy;
}
}