【Java】手写ArrayList

本文深入分析了Java中ArrayList的源码,包括动态分配、添加、删除等核心功能,并实现了合并和去重合并功能。通过实例演示了如何使用自定义的MyArrayList类,展示了其基本操作和扩展能力。
摘要由CSDN通过智能技术生成

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);
    			}
    		}
    	}
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值