zoukankan      html  css  js  c++  java
  • Java ArrayList的模拟实现

    package test;
    
    import java.util.Arrays;
    import java.util.Collection;
    
    public class MyArrayList<E> {
        
        //存储数据
        private Object[] values;
        
        //已经使用的容量
        private int size;
        
        //修改次数
        private int modCount;
        
        /**
         * 根据给定容量初始化
         * @param initialCapacity
         */
        public MyArrayList(int initialCapacity){
            if(initialCapacity > 0){//按照给定的容量大小初始化数组
                values = new Object[initialCapacity];
            }else if(initialCapacity == 0){
                values = new Object[]{};
            }else{
                throw new IllegalArgumentException("非法初始化容量: "+
                        initialCapacity);
            }
    
        }
        
        /**
         * 默认初始化方法
         */
        public MyArrayList(){
            this(10);
        }
        
        /**
         * 用集合初始化一个ArrayList
         * @param c
         */
        public MyArrayList(Collection c){
            values = c.toArray();
            if (values.length != 0) {
                size = values.length;
                if (values.getClass() != Object[].class)
                    values = Arrays.copyOf(values, size, Object[].class);
            }else{
                values = new Object[]{};
            }
        }
        /**
         * 检查是否数组越界了
         * @param index
         */
        private void rangeCheck(int index) {
            if (index >= size || index < 0)
                throw new IndexOutOfBoundsException("数组越界了");
        }
        
        /**
         * 替换原数组中的值,并且将原值返回
         * @param index
         * @param element
         * @return
         */
        public E set(int index,E element){
            //检查是否越界
            rangeCheck(index);
            
            E oldValue = (E)values[index];
            values[index] = element;
            
            return oldValue;
        }
        
        /**
         * 在数组的末尾增加一个元素
         * @param element
         */
        public void add(E element){
            //扩容
            ensureCapacity(size+1);
            values[size++] = element;
            
        }
        
        /**
         * @param index
         * @param element
         */
        public void add(int index,E element){
            //先检查数组的下标是否越界了
            rangeCheck(index);
            //扩容
            ensureCapacity(size+1);
            
            Object[] oldValues = values;
            values[index] = element;
            
            //将原数组index后的值拷贝带新数组中
            System.arraycopy(oldValues, index, values, index+1, size-index);
            
            size++;
            
        }
        
        /**
         * 将一个collection中的元素添加到数组末尾
         * @param c
         */
        public void addAll(Collection c){
            Object[] cArray = c.toArray();
            
            //扩容
            ensureCapacity(size+cArray.length);
            
            //将传入数据拷贝到数组末尾
            System.arraycopy(cArray, 0, values, size, cArray.length);
            
            size += cArray.length;
        }
        
        /**
         * 将一个collection中的元素添加到数组的指定位置
         * @param index
         * @param c
         */
        public void addAll(int index,Collection c){
            //先检查数组的下标是否越界了
            rangeCheck(index);
            //扩容
            Object[] cArray = c.toArray();
            int cLength = cArray.length;
            
            ensureCapacity(size+cLength);
            
            Object[] oldValues = values;
            //将传入数据拷贝到数组指定位置
            System.arraycopy(cArray, 0, values, index, cLength);
            
            //将原数组中index以后的数据拷贝过来
            System.arraycopy(oldValues, index, values, values.length-1, size-index);
            
            size += cLength;
            
        }
        
        /**
         * 根据下标获取元素
         * @param index
         * @return
         */
        public E get(int index){
            //先检查数组的下标是否越界了
            rangeCheck(index);
            
            E e = (E) values[index];
            
            return e;
            
        }
        
        /**
         * 根据下标删除元素
         * @param index
         * @return
         */
        public E remove(int index){
            //先检查数组的下标是否越界了
            rangeCheck(index);
            
            E removeValue = (E) values[index];
            
            System.arraycopy(values, index+1, values, index, size-index-1);
            
            //置为空,gc回收
            values[size--] = null;
            
            return removeValue;
            
        }
        
        /**
         * 根据对象删除
         * @param o
         */
        public void remove(Object o){
            //考虑元素为null的情况
            if(null == o){
                for (int i = 0; i < size; i++) {
                    if(values[i] == null){
                        remove(i);
                    }
                }
                
            }else{
                for (int i = 0; i < size; i++) {
                    if(values[i].equals(o)){
                        remove(i);
                    }
                }
                
            }
        }
        
        /**
         * 扩容方法,保证数组的长度足够
         * @param minCapacity
         */
        public void ensureCapacity(int minCapacity){
            modCount++;
            
            int oldCapacity = values.length;
            if (minCapacity > oldCapacity) {
                //先默认扩容50%+1,如果还是不能满足,则直接用传入的所需容量
                int newCapacity = (oldCapacity*3)/2+1;
                if(newCapacity < minCapacity){
                    newCapacity = minCapacity;
                }
                
                values = Arrays.copyOf(values, newCapacity);
                
            }
        }
        
        public int size(){
            return size;
        }
    
        
    
    }

    最后再介绍一下ensureCapacity这个方法的想法(从网上看到的):

    我们知道ArrayList的内部是采用数组来存储元素的,由于java数组都是定长的,所以这个数组的大小一定是固定的,这个大小就是capacity。我们可以肯定capacity一定是大于或等于ArrayList的size,那么当size不断增加到了要超过capacity的时候,ArrayList就不得不重新创建新的capacity来容纳更多的元素,这时需要首先建立一个更长的数组,将原来的数组中的元素复制到新数组中,再删除原来的数组。可见当ArrayList越来越大时,这种操作的消耗也是越来越大的。
    为了减少这种不必要的重建capacity的操作,当我们能肯定ArrayList大致有多大(或者至少会有多大)时,我们可以先让ArrayList把capacity设为我们期望的大小,以避免多余的数组重建。
    假设ArrayList自动把capacity设为10,每次重建时将长度递增原来的三分之二,那么当我们需要大约存储50个元素到ArrayList中时,就会大约需要重建数组4次,分别是在增加第11、第17、第26、第39个元素的时候进行的。如果我们一开始就让ArrayList的capacity为50,那么不需要任何数组重建就能完成所有插入操作了。
    java允许我们在构造ArrayList的同时指定capacity,如new ArrayList(50),也允许在以后将它设得更大,而增大capacity就是使用ensureCapacity()方法。注意:capacity只能比原来的更大,而不能比原来的更小,否则java会忽略该操作。ArrayList的初始默认capacity为10,所以给capacity指定小于10的整数是毫无意义的。
    最后说说ArrayList的size,前面说过,size一定小于等于capactiy,而且更重要的是,访问超过size的位置将抛出异常,尽管这个位置可能没有超过capacity。ensureCapacity()只可能增加capacity,而不会对size有任何影响。要增加size,只能用add()方法。

  • 相关阅读:
    LeetCode刷题7——数字的补数
    Leetcode刷题6—不同路径
    Leetcode刷题5—最大子序和
    LeetCode刷题4——子集
    LeetCode刷题3——位1的个数
    LeetCode刷题2——颠倒二进制位
    小鸡啄米问题求解
    weavenet
    为系统守护进程预留计算资源
    PolicyRouting (ip rule)
  • 原文地址:https://www.cnblogs.com/dengyulinBlog/p/7090242.html
Copyright © 2011-2022 走看看