ArrayList源码分析

构造方法

ConstructorConstructor描述
ArrayList()构造一个初始容量为十的空列表。
ArrayList(int initialCapacity)构造具有指定初始容量的空列表。
ArrayList(Collection<? extendsE> c)构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
ArrayList()
public class Test01 {

	public static void main(String[] args) {
		//这行代码做了什么?
		//真的构造一个初始容量为十的空列表?
		ArrayList<String> list = new ArrayList<String>();
	}
}
  • 源码
public class ArrayList<E> {

	/**
	 * 默认初始容量
	 */
	private static final int DEFAULT_CAPACITY = 10;
	/**
	 * 空数组
	 */
	private static final Object[] EMPTY_ELEMENTDATA = {};
	/**
	 * 默认容量的空数组
	 */
	private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
	/**
	 * 集合真正存储数组元素的数组
	 */
	transient Object[] elementData;
	/**
	 * 集合的大小
	 */
	private int size;

	public ArrayList() {
		this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
	}
}

Q: 默认空容量,是什么时候放进去的?

ArrayList(int initialCapacity)
public class Test01 {

	public static void main(String[] args) {
		//这行代码ArrayList底层做了什么?
		ArrayList<String> list = new ArrayList<String>(5);
	}
}
  • 源码
public class ArrayList<E> {

	public ArrayList(int initialCapacity) { //initialCapacity = 5
		//判断初始容量initialCapacity是否大于0
		if (initialCapacity > 0) {
			//创建一个数组,且指定长度为initialCapacity
			this.elementData = new Object[initialCapacity];
		} else if (initialCapacity == 0) {
			//如果initialCapacity容量为0,把EMPTY_ELEMENTDATA的地址赋值给elementData
			this.elementData = EMPTY_ELEMENTDATA;
		} else {
			//以上两个条件都不满足报错
			throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
		}
	}
}
ArrayList(Collection<? extends E> c)
public class Test01 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<String>();
		list.add("aaa");
		list.add("bbb");
		list.add("ccc");
		//这行代码做了什么?
		ArrayList<String> list1 = new ArrayList<>(list);
		for (String s : list1) {
			System.out.println(s);
		}
	}
}
  • 源码
public class ArrayList<E> {

	public ArrayList(Collection<? extends E> c) {
		// 将集合构造中的集合对象转成数组,且将数组的地址赋值给elementData
		elementData = c.toArray();
		// 将elementData的长度赋值给 集合长度size,且判断是否不等于 0
		if ((size = elementData.length) != 0) {
			// 判断elementData 和 Object[] 是否为不一样的类型
			if (elementData.getClass() != Object[].class)
				//如果不一样,使用Arrays的copyOf方法进行元素的拷贝
				elementData = Arrays.copyOf(elementData, size, Object[].class);
		} else {
			// 用空数组代替
			this.elementData = EMPTY_ELEMENTDATA;
		}
	}

	//将集合转数组的方法
	public Object[] toArray() {
		//调用数组工具类方法进行拷贝
		return Arrays.copyOf(elementData, size);
	}
}

//数组工具类
public class Arrays {

	public static <T> T[] copyOf(T[] original, int newLength) {
		//再次调用方法进行拷贝
		return (T[]) copyOf(original, newLength, original.getClass());
	}

	public static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
		//用三元运算符进行判断,不管结果如何都是创建一个新数组
		T[] copy = ((Object) newType == (Object) Object[].class) ?
				(T[]) new Object[newLength] :
				(T[]) Array.newInstance(newType.getComponentType(), newLength);
		//将数组的内容拷贝到 copy 该数组中
		System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
		//返回拷贝元素成功后的数组
		return copy;
	}
}

R:复制前提: 长度大与0 && 集合元素类型不为Object.class()?

添加方法

方法名描述
public boolean add(E e)将指定的元素追加到此列表的末尾。
public void add(int index, E element)在此列表中的指定位置插入指定的元素。
public boolean addAll(Collection<?extends E> c)按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
public boolean addAll(i nt index,Collection<? extends E> c)将指定集合中的所有元素插入到此列表中,从指定的位置开始。
public boolean add(E e)
public class Test01 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("黑马程序员");
	}
}
  • 源码
public class ArrayList<E> {

	//将添加的数据传入给 e
	public boolean add(E e) {
		//调用方法对内部容量进行校验-》size为目前集合的长度,方法为新增操作,长度+1
		ensureCapacityInternal(size + 1);
		//将元素添加到末尾,并且将长度加1
		elementData[size++] = e;
		return true;
	}

	/**
	 *
	 * @param minCapacity : 数组容量:最小也的这么大
	 */
	private void ensureCapacityInternal(int minCapacity) {
		//判断集合存数据的数组是否等于空容量的数组
		if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
			//通过最小容量和默认容量 求出较大值 (用于第一次扩容)
			minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
		}
		//将if中计算出来的容量传递给下一个方法,继续校验
		ensureExplicitCapacity(minCapacity);
	}

	/**
	 *
	 * @param minCapacity : 数组容量:最小也的这么大
	 */
	private void ensureExplicitCapacity(int minCapacity) {
		//实际修改集合次数++ (在扩容的过程中没用,主要是用于迭代器中)
		modCount++;
		//判断最小容量 - 数组长度是否大于 0
		if (minCapacity - elementData.length > 0)
			//到此说明容量不够
			//将第一次计算出来的容量传递给 核心扩容方法
			grow(minCapacity);
	}

	private void grow(int minCapacity) {
		//记录数组的实际长度,此时由于木有存储元素,长度为0
		int oldCapacity = elementData.length;
		//核心扩容算法 原容量的1.5倍
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		//判断新容量 - 最小容量 是否小于 0, 如果是第一次调用add方法必然小于
		if (newCapacity - minCapacity < 0)
			//还是将最小容量赋值给新容量
			newCapacity = minCapacity;
		//判断新容量-最大数组大小 是否>0,如果条件满足就计算出一个超大容量
		if (newCapacity - MAX_ARRAY_SIZE > 0)
			newCapacity = hugeCapacity(minCapacity);
		// 调用数组工具类方法,创建一个新数组,将新数组的地址赋值给elementData
		elementData = Arrays.copyOf(elementData, newCapacity);
	}
}
public void add(int index, E element)
public class Test01 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("111");
		list.add("222");
		list.add("333");
		list.add(1, "444");
		System.out.println(list);
	}
}
  • 源码
public class ArrayList<E> {

	public void add(int index, E element) {
		//添加范围检查
		rangeCheckForAdd(index);
		//调用方法检验是否要扩容,且让增量++
		ensureCapacityInternal(size + 1);
		/**
		 * 核心实现:在index插入元素,先把之前在index做为起始,直到末尾的尾段段数据,向后移一位
		 */
		System.arraycopy(elementData, index, elementData, index + 1, size - index);
		elementData[index] = element;
		size++;
	}

	private void rangeCheckForAdd(int index) {
		//超出指定范围就报错
		if (index > size || index < 0)
			throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}

	private void ensureCapacityInternal(int minCapacity) {
		if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
			minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
		}
		//确保明确的能力
		ensureExplicitCapacity(minCapacity);
	}

	private void ensureExplicitCapacity(int minCapacity) {
		//增量++ (也就是实际修改集合的次数)
		modCount++;
		//如果再调用 add(index,element) 方法之前已经扩容,那么源码跟踪到此结束
		//不会进行扩容
		if (minCapacity - elementData.length > 0)
			grow(minCapacity);
	}
}
arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
public final class System {
	参数
	src - 源数组。
	srcPos - 源数组中的起始位置。
	dest - 目标数组。
	destPos - 目的地数据中的起始位置。
	length - 要复制的数组元素的数量。
	public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
}
  • 将 src 数组,从 srcPos 位置起始的 length,复制到目标数组 dest,复制的起始位置为 destPos
public boolean addAll(Collection<?extends E> c)
public class Test01 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("黑马程序员");
		list.add("传智播客");
		list.add("传智大学");
		ArrayList<String> list1 = new ArrayList<>();
		list1.addAll(list);
		System.out.println(list);
		System.out.println(list1);
	}
}
  • 源码
public class ArrayList<E> {

	public boolean addAll(Collection<? extends E> c) {
		//把集合的元素转存到Object类型的数组中
		Object[] a = c.toArray();
		//记录数组的长度
		int numNew = a.length;
		//调用方法检验是否要扩容,且让增量++
		ensureCapacityInternal(size + numNew);
		//调用方法将a数组的元素拷贝到elementData数组中--》将目标数组拼接在原数组的尾部
		System.arraycopy(a, 0, elementData, size, numNew);
		//集合的长度+=a数组的长度
		size += numNew;
		//只要a数组的长度不等于0,即说明添加成功
		return numNew != 0;
	}
}
public boolean addAll(int index, Collection<? extends E> c)
public class Test01 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("黑马程序员");
		list.add("传智播客");
		list.add("传智大学");
		ArrayList<String> list1 = new ArrayList<>();
		list1.add("酷丁鱼");
		//在指定索引处添加一个集合list1.addAll(1,list);
		System.out.println(list);
		System.out.println(list1);
	}
}
  • 源码
public class ArrayList<E> {
	//长度为0的空数组
	private static final Object[] EMPTY_ELEMENTDATA = {};
	//默认容量为空的数组
	private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
	//集合存元素的数组
	Object[] elementData;
	//集合的长度
	private int size;
	//默认的容量
	private static final int DEFAULT_CAPACITY = 10;
	public boolean addAll(int index, Collection<? extends E> c) {
		//校验索引
		rangeCheckForAdd(index);
		//将数据源转成数组
		Object[] a = c.toArray();
		//记录数据源的长度 3
		int numNew = a.length;
		//目的就是为了给集合存储数据的数组进行扩容
		ensureCapacityInternal(size + numNew);
		/**
		 * 先把位置空出来,然后将数组进行填充
		 */
		//numMoved:代表要移动元素的个数 --> 1个
		//numMoved: 数据目的(集合list1)的长度-调用addAll的第一个参数 (索引1)
		int numMoved = size - index;
		//判断需要移动的个数是否大于0
		if (numMoved > 0)
			//使用System中的方法arraycopy进行移动
			System.arraycopy(elementData, index, elementData, index + numNew,
							 numMoved);
		//才是真正将数据源(list)中的所有数据添加到数据目的(lsit1)
		System.arraycopy(a, 0, elementData, index, numNew);
		size += numNew;
		return numNew != 0;
	}
	private void rangeCheckForAdd(int index) {
		if (index > size || index < 0)
			throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}
}

删除方法

public E remove(int index) 按索引位置移除
public class Test01 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("山东大李逵");
		list.add("天魁星宋江");
		list.add("天罡星卢俊义");
		list.add("西门大人");
		//根据索引删除元素
		String value = list.remove(3);
		System.out.println("删除的元素为: " + value);
		System.out.println("集合的元素: " + list);
	}
}
  • 源码
public class ArrayList<E> {

	public E remove(int index) {
		//范围校验
		rangeCheck(index);
		//增量++
		modCount++;
		//将index对应的元素赋值给 oldValue
		E oldValue = elementData(index);
		//计算集合需要移动元素个数
		int numMoved = size - index - 1;
		//如果需要移动元素个数大于0,就使用arrayCopy方法进行拷贝
		//注意:数据源和数据目的就是elementData
		if (numMoved > 0)
			System.arraycopy(elementData, index + 1, elementData, index, numMoved);
		//将源集合最后一个元素置为null,尽早让垃圾回收机制对其进行回收
		//数组长度要减1 && 末尾元素要置空
		elementData[--size] = null;
		//返回被删除的元素
		return oldValue;
	}
}
public boolean remove(Object o) 按对象进行移除
public class Test01 {

	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("山东大李逵");
		list.add("天魁星宋江");
		list.add("西门大人");
		list.add("天罡星卢俊义");
		//根据索引删除元素boolean flag = list.remove("西门大人");
		System.out.println("是否删除成功: " + flag);
		System.out.println("集合的元素: " + list);
	}
}
  • 源码
public class ArrayList<E> {

	public boolean remove(Object o) {
		//判断要删除的元素是否为null
		if (o == null) {
			//遍历集合
			for (int index = 0; index < size; index++)
				//判断集合的元素是否为null
				if (elementData[index] == null) {
					//如果相等,调用fastRemove方法快速删除
					fastRemove(index);
					return true;
				}
		} else {
			//遍历集合
			for (int index = 0; index < size; index++)
				//用o对象的equals方法和集合每一个元素进行比较
				if (o.equals(elementData[index])) {
					//如果相等,调用fastRemove方法快速删除
					fastRemove(index);
					return true;
				}
		}
		//如果集合没有o该元素,那么就会返回false
		return false;
	}

	//快速删除:数据移动
	private void fastRemove(int index) {//增量++
		modCount++;
		//计算集合需要移动元素的个数
		int numMoved = size - index - 1;
		//如果需要移动的个数大于0,调用arrayCopy方法进行拷贝
		if (numMoved > 0)
			System.arraycopy(elementData, index + 1, elementData, index, numMoved);
		//将集合最后一个元素置为null,尽早被释放
		elementData[--size] = null;
	}
}

修改方法

public E set(int index, E element) 根据索引修改集合元素
public class Test01 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("山东大李逵");
		list.add("天魁星宋江");
		list.add("天罡星卢俊义");
		list.add("西门大人");
		//根据索引修改集合元素
		String value = list.set(3, "花和尚鲁智深");
		System.out.println("set方法返回值: "+value);
		System.out.println("集合的元素: "+list);
	}
}
  • 源码
public class ArrayList<E> {

	public E set(int index, E element) {
		//范围校验
		rangeCheck(index);
		//先取出index对应的元素,且赋值给oldValue
		E oldValue = elementData(index);
		//将element直接覆盖index对应的元素
		elementData[index] = element;
		//返回被覆盖的元素
		return oldValue;
	}

	private void rangeCheck(int index) {
		if (index >= size)
			throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}
}

获取方法

public E get(int index) 根据索引获取元素
public class Test01 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		list.add("山东大李逵");
		list.add("天魁星宋江");
		list.add("天罡星卢俊义");
		list.add("西门大人");
		//根据索引获取集合元素
		String value = list.get(1);
		System.out.println("get方法返回值: "+value);
		System.out.println("集合的元素: "+list);
	}
}
  • 源码
public class ArrayList<E> {
	public E get(int index) {
		//范围校验
		rangeCheck(index);
		//直接根据索引取出集合元素
		return elementData(index);
	}
	private void rangeCheck(int index) {
		if (index >= size)
			throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
	}
}

清空方法

public void clear() 清空集合所有数据
public class Test01 {

	public static void main(String[] args) {
		//创建集合对象
		List<String> list = new ArrayList<String>();
		//添加元素
		list.add("hello");
		list.add("PHP");
		list.add("Java");
		System.out.println("清空前的集合: " + list);
		//清空集合所有元素
		list.clear();
		System.out.println("清空后的集合: " + list);
	}
}
  • 源码
public class ArrayList<E> {
	public void clear() {
		//实际修改集合次数++
		modCount++;
		//遍历集合,将集合每一个索引对应位置上的元素都置为null,尽早让其释放
		for (int i = 0; i < size; i++)
			elementData[i] = null;
		//集合长度更改为0
		size = 0;
	}
}

包含方法

public boolean contains(Object o) 判断集合是否包含指定元素
public class Test01 {

	public static void main(String[] args) {
		//创建集合对象
		List<String> list = new ArrayList<String>();
		//添加元素
		list.add("hello");
		list.add("PHP");
		list.add("Java");
		System.out.println("判断之前集合的元素: " + list);
		//需求:如果集合中没有JavaSE该元素,请添加一个JavaSE元素
		//解决方式一:循环遍历集合,判断集合是否包含JavaSE,如果没有包含就调用集合的add方法进行添加操作
		//解决方式二:使用集合contains方法判断,根据判断的结果决定是否要添加元素
		if (!list.contains("JavaSE")) {
			list.add("JavaSE");
		}
		System.out.println("判断之后集合的元素: " + list);
	}
}
  • 源码
public class ArrayList<E> {

	//源码contains方法
	public boolean contains(Object o) {
		//调用indexOf方法进行查找
		return indexOf(o) >= 0;
	}

	public int indexOf(Object o) {
		//如果元素是null,也进行遍历操作
		//因为集合中有可能够会存储null
		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;
		}
		//如果没有走if,也没有走else,那么就说明o该元素在集合中不存在
		return -1;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值