ArrayList常用Api分析及注意事项

博客 动态
0 230
优雅殿下
优雅殿下 2022-05-23 14:59:33
悬赏:0 积分 收藏

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在多线程环境中是不安全的
posted @ 2022-05-23 14:16 乌托拉赛文 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员