JAVA集合-ArrayList

 JDK1.8,代码:java.util.ArrayList.java

ArrayList

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

ArrayList实现了List、RandomAccess接口。可以插入空数据,也支持随机访问。

 

/**
 * 序列化的版本号
 */
private static final long serialVersionUID = 8683452581122892189L;

/**
 * 默认初始容量10
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * 用于空实例的共享空数组实例
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * 用于默认大小的空实例的共享空数组实例
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * 存储ArrayList元素的数组缓冲区
 */
transient Object[] elementData; 

/**
 * ArrayList的大小
 */
private int size;

构造函数

/**
 * 用初始容量作为参数的构造方法
 */
public ArrayList(int initialCapacity) {
	if (initialCapacity > 0) {
		//初始容量大于0,实例化数组
		this.elementData = new Object[initialCapacity];
	} else if (initialCapacity == 0) {
		//初始容量等于0,赋予空数组
		this.elementData = EMPTY_ELEMENTDATA;
	} else {
		throw new IllegalArgumentException("Illegal Capacity: "+
										   initialCapacity);
	}
}

/**
 * 无参的构造方法
 */
public ArrayList() {
	this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * 构造一个包含指定元素的列表集合
 * 按照集合返回它们的顺序迭代器
 *
 * 要将其元素放入此列表的集合;如果指定的集合为空,抛出NullPointerException
 */
public ArrayList(Collection<? extends E> c) {
	elementData = c.toArray(); // c为空会抛出NullPointerException
	if ((size = elementData.length) != 0) {
		if (elementData.getClass() != Object[].class)
			elementData = Arrays.copyOf(elementData, size, Object[].class);
	} else {
		// 用空数组替换
		this.elementData = EMPTY_ELEMENTDATA;
	}
}

构造方法指定元素列表集合示例:

package com.container.arraylist;

import java.util.ArrayList;

/**
 * @Classname ArrayListDemo
 * @Description 构造方法指定元素列表集合示例
 * @Date 2019/10/19 13:01
 * @Created by xiangty
 */
public class ArrayListDemo {

    public static void main(String[] args) {
        ArrayList<A> arrayList = new ArrayList<A>();

        A a = null;
        for (int i = 0; i < 10; i++) {
            a = new A();
            a.setA("addValue" + i);
            arrayList.add(a);
        }

        ArrayList arrayList2 = new ArrayList(arrayList);
        // 打印arrayList2集合的值
        print(arrayList2);
    }

    public static void demo1() {
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        for (int i = 0; i < 10; i++) {
            arrayList.add(i);
        }

        ArrayList arrayList2 = new ArrayList(arrayList);
        // 打印arrayList2集合的值
        print(arrayList2);
    }

    public static <E> void print(ArrayList<E> arrayList){
        arrayList.forEach((a) -> System.out.println(a));
    }

}

class A {
    private String A;

    public String getA() {
        return A;
    }

    public void setA(String a) {
        A = a;
    }

    @Override
    public String toString() {
        return "A{" +
                "A='" + A + '\'' +
                '}';
    }

}

从上述的构造方法中可知,默认情况下elementData是一个大小为0的空数组,当指定大小的时候,elementData的初始化大小變成了指定的初始化。

ArrayList扩容

ArrayList相当于动态数据,其中最重要的两个属性:elementData 数组和 size 大小。

add(E e)新增方法

/**
 * 将指定的元素追加到此列表的末尾
 */
public boolean add(E e) {
	ensureCapacityInternal(size + 1);  // Increments modCount!!
	elementData[size++] = e;
	return true;
}

首先进行扩容校验

将插入的值放到尾部,并将 size + 1 

add(int index, E element)指定位置添加

public void add(int index, E element) {
	rangeCheckForAdd(index);

	ensureCapacityInternal(size + 1);  // Increments modCount!!
	//复制,向后移动
	System.arraycopy(elementData, index, elementData, index + 1,
					 size - index);
	elementData[index] = element;
	size++;
}

也是首先扩容校验

接着对数据进行复制,目的是把 index 位置空出来放本次插入的数据,并将后面的数据向后移动一个位置

ensureCapacityInternal方法

/**
 * 确保内部容量
 */
private void ensureCapacityInternal(int minCapacity) {
	//先判断数组是否为空
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
		//如果数组为空,将DEFAULT_CAPACITY(为10)和minCapacity中较大的一个赋值给minCapacity
		minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
	}
	ensureExplicitCapacity(minCapacity);
}

a).当空列表add()第1个元素时,调试可知:原本minCapacity为1,在Math.max()方法比较后,minCapacity为10。

b).但当add()第2个元素时,数组非空,直接进入ensureExplicitCapacity(minCapacity)(此时minCapacity为2)。

ensureExplicitCapacity方法

private void ensureExplicitCapacity(int minCapacity) {
	//定义于ArrayList的父类AbstractList,用于存储结构修改次数
	modCount++;

	// overflow-conscious code
	if (minCapacity - elementData.length > 0)
		//如果数组的长度(elementData.length)小于最小容量(minCapacity),就扩容
		grow(minCapacity);
}

a).当要add第1个元素时,这时elementData.length(为0,因为此时还是空列表)是要比minCapacity(为10)小的,会进入grow(minCapacity)方法(minCapacity为10)

b).当add第2个元素时,调试可知:minCapacity为2,此时elementData.length(即是容量)在添加第一个元素后扩容成10了,比minCapacity大,不会去执行grow方法 。数组容量仍为10。

c).所以当添加第3、4···到第10个元素时,依然不会执行grow方法,数组容量都为10。

d).直到添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进入grow方法进行扩容
 

grow方法进行扩容

/**
 * 用来分配数组的size最大值
 */
private void grow(int minCapacity) {
	// overflow-conscious code
	int oldCapacity = elementData.length;
	/*
		右移一位相当于原数除以2,位运算的计算方式相对除以计算更快  
		新容量扩大为原来容量的1.5
	*/
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	if (newCapacity - minCapacity < 0)
		//从minCapacity和这个newCapacity中取较大值作为扩容后的新数组长度(新容量)。
		newCapacity = minCapacity;
		
	if (newCapacity - MAX_ARRAY_SIZE > 0)
		//如果新容量大于数组的最大size,进入hugeCapacity方法
		newCapacity = hugeCapacity(minCapacity);
		
	//将原来数组的数据复制到新的数组中
	elementData = Arrays.copyOf(elementData, newCapacity);
}

当add第1个元素时,oldCapacity为0,经比较后第一个if判断成立,newCapacity = minCapacity(为10)。但是第二个if判断不会成立,即newCapacity 不比 MAX_ARRAY_SIZE大,则不会进入hugeCapacity方法。数组容量为10,add方法中return true,size增为1

第3、4···到第10个元素逻辑同第1个

当add第11个元素时,newCapacity为15,比minCapacity(为11)大,第一个if判断不成立。新容量没有大于数组最大size,不会进入hugeCapacity方法。数组容量扩为15,add方法中return true,size增为11法最后一步,在确定好新数组的大小后,会调用Arrays.copyOf()方法,以适当长度(newCapacity)新建一个原数组的拷贝,并修改原数组,指向这个新建数组

 

grow()方法最后一步,在确定好新数组的大小后,会调用Arrays.copyOf()方法,以适当长度(newCapacity)新建一个原数组的拷贝,并修改原数组,指向这个新建数组。java垃圾回收机制会自动回收原数组

elementData = Arrays.copyOf(elementData, newCapacity);

hugeCapacity方法

private static int hugeCapacity(int minCapacity) {
	if (minCapacity < 0) // overflow
		throw new OutOfMemoryError();
		
	//对minCapacity和MAX_ARRAY_SIZE进行比较
	//若minCapacity大,将Integer.MAX_VALUE作为新数组的大小
	//若MAX_ARRAY_SIZE大,将MAX_ARRAY_SIZE作为新数组的大小
	return (minCapacity > MAX_ARRAY_SIZE) ?
		Integer.MAX_VALUE :
		MAX_ARRAY_SIZE;
}

ensureCapacity方法

add方法添加大量数据的时候,为减少分配次数和提高效率,推荐使用ensureCapacity方法

public void ensureCapacity(int minCapacity) {
	int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
		// any size if not default element table
		? 0
		// larger than default for default empty table. It's already
		// supposed to be at default size.
		: DEFAULT_CAPACITY;

	if (minCapacity > minExpand) {
		ensureExplicitCapacity(minCapacity);
	}
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值