ArrayList作为java中常用的数据结构,很有自己重现一遍的必要,这里只是针对于ArrayList的源码进行了分析,提取了其中动态分配,添加,删除等核心功能,并加入了合并及去重合并的功能。希望在以后能够搭建动态数组模型对于具体问题具体解决。
-
接口部分:定义通用方法
public interface MyList<E> { public void add(E element); public void add(int index,E element); public E remove(int index); public boolean remove(Object element); public E get(int index); public int size(); public void set(int index, E element); public boolean contains(Object o); } -
实现部分:
public class MyArrayList<E> implements MyList<E>{ // 代码测试模块 // public static void main(String[] args) { // MyArrayList<String> list1 = new MyArrayList<>(); // list1.add("1"); // list1.add("2"); // MyArrayList<String> list2 = new MyArrayList<>(); // list2.add("1"); // list2.add("2"); // list1.DeListMerge(list2); // for (int i = 0; i < list1.size(); i++) { // System.out.print(list1.get(i)); // } // // } // 缺省容量 private static final int DEFAULT_CAPACITY = 10; // 空对象数组 用于监测作用数组是否为空 private static final Object[] EMPTY_ELEMENTDATA = {}; // 元素数组 private transient Object[] elementData; // 最大数组容量 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 数组大小 private int size; /** * 有参构造方法 * @param initialCapacity 参数为数组初始大小 */ public MyArrayList(int initialCapacity) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** * 无参构造方法 * 构造缺省容量大小数组 */ public MyArrayList() { this(DEFAULT_CAPACITY); } /** * 以元素形式返回对应索引元素 * @param index * @return */ private E elementData(int index) { return (E) elementData[index]; } /** * 添加操作核心代码:确保容量 * 步骤: 1.数组为空检测:小于缺省容量则赋予最小容量缺省容量大小 * 2.容量是否足够检测: 不足则需要进行扩容 * @param minCapacity 所需最小容量 */ private void ensureCapacity(int minCapacity) { if (elementData == EMPTY_ELEMENTDATA) { //判断初始化的elementData为空数组时,设定最小容量为缺省容量和最小容量中较大的一个 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } if(minCapacity > elementData.length) { //判断所需最小容量大于数组长度时,进行数组扩容 grow(minCapacity); } } /** * 数组容量边界处理 * @param minCapacity * @return 当所需最小容量仍超出设定的MAX_ARRAY_SIZE最大容量,则返回,int的极限 */ private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** * 数组扩容 * @param minCapacity */ private void grow(int minCapacity) { int oldCapacity = elementData.length; //将扩充前的elementData大小给oldCapacity int newCapacity = oldCapacity + (oldCapacity >> 1);//>>1移位运算提高除法运算效率 设置新容量为老容量的1.5倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) //新容量超出数组最大限制检测 newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); //赋值扩容后的数组回原数组 } /** * 添加操作索引范围检测(可以等于数组大小) * @param index */ private void rangeCheckForAdd(int index) { if (index < 0 || index > this.size) throw new IndexOutOfBoundsException(); } /** * 索引范围检测 * @param index */ private void rangeCheck(int index) { if (index < 0 || index >= this.size) throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); } /** * 无索引的添加方法 * 步骤: 1.确保添加后容量足够 * 2.在数组最后添加元素 */ @Override public void add(E element) { ensureCapacity(size + 1); elementData[size++] = element; } /** * 有索引的添加方法 * 步骤: 1.索引是否合法检测 * 2.确保添加后容量足够 * 3.将插入元素位置后所有元素后移一位 * 4.在索引位置插入元素 */ @Override public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacity(size + 1); System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } /** * 通过索引的移除方法 * 步骤: 1.检测索引是否合法 * 2.计算移动位数,将索引位置后所有元素向前移一位,置空数组最后一位 * 3.返回移除的元素 */ @Override public E remove(int index) { rangeCheck(index);//检查index的合理性 E oldValue = elementData(index);//通过索引直接找到该元素 int numMoved = size - index - 1;//计算要移动的位数。 if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; return oldValue; } /** * 通过对象的移除方法 * 步骤: 1.分两种情况:对象为空和对象不为空 * 2.遍历数组,移除对象,成功返回true,否则返回false */ @Override public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { remove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { remove(index); return true; } } return false; } /** * 获取对象 */ @Override public E get(int index) { rangeCheck(index); return elementData(index); } /** * 获取数组大小 */ @Override public int size() { return this.size; } /** * 设置索引位置的元素 */ @Override public void set(int index, E element) { rangeCheck(index); elementData[index] = element; } /** * 获取对象索引 * @param o * @return */ public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; } /** * 对象是否存在 */ public boolean contains(Object o) { return indexOf(o) >= 0; } /** * 合并 * @param list */ public void listMerge(MyArrayList<E> list){ ensureCapacity(size + list.size()); for (int i = 0; i < list.size(); i++) { elementData[size+i] = list.get(i); } size = size + list.size(); } /** * 去重合并 * @param list */ public void DeListMerge(MyArrayList<E> list){ for (int i = 0; i < list.size; i++) { E element = list.get(i); if (!contains(element)) { add(element); } } } }
本文深入分析了Java中ArrayList的源码,包括动态分配、添加、删除等核心功能,并实现了合并和去重合并功能。通过实例演示了如何使用自定义的MyArrayList类,展示了其基本操作和扩展能力。

5538

被折叠的 条评论
为什么被折叠?



