目標(biāo):手動(dòng)實(shí)現(xiàn)一個(gè)動(dòng)態(tài)數(shù)組脊阴,模擬ArrayList
ArrayList會(huì)自動(dòng)擴(kuò)容豁陆,先來(lái)看一下ArrayList擴(kuò)容規(guī)律扭吁,size()方法只能得到存儲(chǔ)元素的個(gè)數(shù)端圈,得不到List的容量大小炫掐,我們要想辦法:
public static void main(String[] args) throws Exception {
//構(gòu)建一個(gè)初始容量為3的ArrayList對(duì)象
List<Integer> list = new ArrayList<>(3);
//通過(guò)源碼可知ArrayList的元素存儲(chǔ)在Object[] elementData成員數(shù)組中又兵,通過(guò)反射可得到該成員變量
Class<? extends List> clazz = list.getClass();
Field f = clazz.getDeclaredField("elementData");
f.setAccessible(true);
//循環(huán)增加添加元素,同時(shí)通過(guò)反射得到elementData成員,并將每一次遍歷的所得到的elementData數(shù)組長(zhǎng)度添加到Set集合中(利用Set去重)
Set<Integer> addSet = new HashSet<>();
for (int i = 0; i < 100; i++) {
list.add(i);
Object[] objects = (Object[]) f.get(list);
addSet.add(objects.length);
}
//循環(huán)遍歷Set沛厨,將Set元素轉(zhuǎn)動(dòng)到一個(gè)List中(因Set存儲(chǔ)的元素?zé)o序宙地,不方便查看)
List<Integer> addList = new ArrayList<>();
for (Integer i : addSet) {
addList.add(i);
}
//List排序并打印
Collections.sort(addList);
for (Integer i : addList) {
System.out.print(i + " ");
}
System.out.println();
//移除元素,查看elementData長(zhǎng)度變化逆皮,思路同上
Set<Integer> removeSet = new HashSet<>();
for (int i = list.size() - 1; i >= 0; i--) {
list.remove(i);
Object[] objects = (Object[]) f.get(list);
removeSet.add(objects.length);
}
List<Integer> removeList = new ArrayList<>();
for (Integer i : removeSet) {
removeList.add(i);
}
Collections.sort(removeList);
for (Integer i : removeList) {
System.out.print(i + " ");
}
}
運(yùn)行得到結(jié)果:
3 4 6 9 13 19 28 42 63 94 141
141
規(guī)律:
- 添加元素時(shí)宅粥,容量變化規(guī)律:擴(kuò)容后容量 = 當(dāng)前容量 * 3 / 2,再向下取整电谣;改變初始容量后秽梅,發(fā)現(xiàn)規(guī)律相同
- 移除元素時(shí),容量不會(huì)縮減
根據(jù)上面規(guī)律剿牺,實(shí)現(xiàn)一個(gè)具備相同擴(kuò)容規(guī)律的動(dòng)態(tài)數(shù)組(由于實(shí)現(xiàn)List接口企垦,需重寫(xiě)方法太多,這里就不實(shí)現(xiàn)List接口了晒来,只模擬增刪改查的方法):
public class MyList<E> {
//當(dāng)前List的元素個(gè)數(shù)
private int size;
//默認(rèn)容量
private static final int DEFAULT_INIT_CAPACITY = 10;
//數(shù)組
private Object[] elementData;
//默認(rèn)構(gòu)造器
public MyList() {
elementData = new Object[DEFAULT_INIT_CAPACITY];
}
//可指定容量的構(gòu)造器
public MyList(int initCapacity) {
elementData = new Object[initCapacity];
}
//添加元素
public void add(E e) {
//添加元素前判斷當(dāng)前元素個(gè)數(shù)和數(shù)組長(zhǎng)度是否相同钞诡,相同則需要擴(kuò)容
if (size == elementData.length) {
Object[] dest = new Object[elementData.length * 3 / 2];
System.arraycopy(elementData, 0, dest, 0, elementData.length);
elementData = dest;
}
elementData[size++] = e;
}
//移除元素
public void remove(int index) {
System.arraycopy(elementData, index + 1, elementData, index, elementData.length - index - 1);
elementData[--size] = null;
}
//修改元素
public void modify(int index, E e) {
//檢查下標(biāo)是否超出范圍
rangeCheck(index);
elementData[index] = e;
}
//查找元素
public E get(int index) {
//檢查下標(biāo)是否超出范圍
rangeCheck(index);
return (E) elementData[index];
}
//范圍檢查
private void rangeCheck(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException("下標(biāo)越界,index:" + index);
}
}
//獲取當(dāng)前存儲(chǔ)元素個(gè)數(shù)
public int size() {
return size;
}
//打印(用于測(cè)試)
public void print() {
System.out.print("[");
for (int i = 0; i < size; i++) {
if (elementData[i] != null) {
if (i != size - 1) {
System.out.print(elementData[i] + ", ");
} else {
System.out.print(elementData[i]);
}
}
}
System.out.println("]");
}
}
測(cè)試結(jié)果:
public static void main(String[] args) {
MyList<String> myList = new MyList<>(10);
myList.add("a");
myList.add("b");
myList.add("c");
System.out.println(myList.size());//3
myList.print();//[a, b, c]
myList.remove(myList.size() - 1);
myList.print();//[a, b]
myList.modify(0, "aa");
myList.print();//[aa, b]
System.out.println(myList.get(1));//b
}