• ArrayList常用Api分析及注意事项


    数组(定长,有序的,随机访问)。ArrayList是Java在数组的基础上进行衍生出来的Java里的一种数据结构,它在拥有数据的特性之外,增加了可变性 (动态数组)。

    属性

    属性 备注
    DEFAULT_CAPACITY 默认初始大小
    EMPTY_ELEMENTDATA 空数组,申明了长度可能为0
    DEFAULTCAPACITY_EMPTY_ELEMENTDATA 空数组 (无参构造时候的默认值)
    elementData 承认数组元素
    size 数组元素数量,注意和Lenth的

    三种构造初始化

    /**
    
    带有参数的构造方法,
    
    如果长度为0 则给一个默认的常量。
    
    */
    public ArrayList(int initialCapacity) {
    	if (initialCapacity > 0) {
    		this.elementData = new Object[initialCapacity];
    	} else if (initialCapacity == 0) {
    		this.elementData = EMPTY_ELEMENTDATA;
    	} else {
    		throw new IllegalArgumentException("Illegal Capacity: "+
    										   initialCapacity);
    	}
    }
    
    /**
    	直接给一个默认的空数组
    */
    public ArrayList() {
    	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
       public ArrayList(Collection<? extends E> c) {
            Object[] a = c.toArray();
            if ((size = a.length) != 0) {
                if (c.getClass() == ArrayList.class) {
                    elementData = a;
                } else {
                    elementData = Arrays.copyOf(a, size, Object[].class);
                }
            } else {
                // replace with empty array.
                elementData = EMPTY_ELEMENTDATA;
            }
        }
    
    

    分析

    以上三种构建,两种有参,一种无参。主要区别就是 DEFAULTCAPACITY_EMPTY_ELEMENTDATAEMPTY_ELEMENTDATA在不同场景分别给值。
    EMPTY_ELEMENTDATA是带参数的构建函数里长度为0的默认共享数组
    DEFAULTCAPACITY_EMPTY_ELEMENTDATA是不带参数构造函数里长度为0的共享数组
    对比老版本的JDK来看,会对初始化数组的时候解决是数度长度为空的情况下会 new Object[initialCapatity]的情况,减少不必要的内存开支。
    在扩容机制也会针对不同的构造出的数组进行不同的扩容机制。

    Add方法

        public boolean add(E e) {
    		//确保容量够不够,扩容机制
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    	
        // step 1
        private void ensureCapacityInternal(int minCapacity) {
            ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
        }
    
    	// step 2. 计算容量
        private static int calculateCapacity(Object[] elementData, int minCapacity) 	{
    		//判断是否是无参构造来的,为10个容量大小
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    		//否则就给即将增长的长度
            return minCapacity;
         }
    	
    	
    	// step 3
        private void ensureExplicitCapacity(int minCapacity) {
    		//修改次数
            modCount++;
    
            // 即将增长的长度比现的数组长度大就扩容
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
    	// step 4
        private void grow(int minCapacity) {
            //原始长度
            int oldCapacity = elementData.length;
    		//新长度 = 原始长度 + (原始长度/2)
            int newCapacity = oldCapacity + (oldCapacity >> 1);
    		
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
    		//尽量不扩容到 Intege 的最大值, 因为有些Vm的设计超过 MAX_ARRAY_SIZE 可能会 OOM错误 (OutOfMemoryError: Requested array size exceeds VM limit)
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            
    		// minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    

    分析

    1. add函数,可以看出来,每次扩容都是本身的 0.5
    2. 最大可以扩容到 Intege最大值,但也是在实际元素数量真的超过 MAX_ARRAY_SIZE的情况下。
    3. 建立不超过MAX_ARRAY_SIZE的原因是 OutOfMemoryError: Requested array size exceeds VM limit
    4. 为了避免开辟过多的数组空间,建立选择带参数的构造函数,以量申请。

    Remove方法

    借助了系统函数

    /**
             *    第一个参数是要被复制的数组
             *
             *   第二个参数是被复制的数字开始复制的下标
             *
             *   第三个参数是目标数组,也就是要把数据放进来的数组
             *
             *   第四个参数是从目标数组第几个下标开始放入数据
             *
             *   第五个参数表示从被复制的数组中拿几个数值放到目标数组中
             */
    
    public static native void arraycopy(Object src,  int  srcPos,
    									Object dest, int destPos,
                                            int length);
    

    把最后一个元素置为null, size = size -1

    elementData[--size] = null; // clear to let GC do its work
    

    注意事项

    1. 禁止在 for``foreach里删除元素。
    2. ArrayList在多线程环境中是不安全的

    __EOF__

  • 本文作者: Savey
  • 本文链接: https://www.cnblogs.com/m78-seven/p/16301040.html
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    用HTML+CSS+JS做一个漂亮简单的游戏网页——全屏游戏美术大赛作品(4个滚动页面)
    使用 NumPy 来模拟随机游走(Random Walk)
    shell编程基础(第14篇:管道符号的妙用)
    剑指 Offer 18. 删除链表的节点【链表】
    Codeforces-1688 C: Manipulating History 【构造】
    2022年全网最全AI绘画产品整理(一共23款,免费的绘画次数用到你手软)
    使用网络数据采集的好处
    java遍历文件夹并生成_sidebar.md
    双核电脑开200线程会崩溃吗?如何解决
    flex布局与float布局
  • 原文地址:https://www.cnblogs.com/m78-seven/p/16301040.html