Java集合ArrayList源码分析(二)

7 篇文章 0 订阅
6 篇文章 0 订阅

一、构造方法
ArrayList有三个构造方法:
ArrayList()
ArrayList(int)
ArrayList(Collection<? extends E>)
1、无参构造方法:

ArrayList中储存数据的其实就是一个数组,这个数组就是elementData,

public ArrayList() {
	super();//调用父类中的无参构造方法,父类中的是一个空的构造方法
	this.elementData = EMPTY_ELEMENTDATA;//是一个空的Object[],将elementData初始化。空的Object[]会默认大小10
}

2、有参构造:

public ArrayList(int initialCapacity) {
	super();//父类中空的构造方法
	if(initalCapacity < 0) {//判断如果自定义大小的容量小于0,则报下面这个非法数据异常
	throw new IllegalArgumentException("Illegal Capacity" + 			initialCapacity);
	this.elementData = Object[initialCapacity]
	//将自定义的容量大小当成初始化elementData的大小。
	}
}

总结:ArrayList的构造方法就做一件事情,就是初始化一下存储数据的容器,其实本质就是一个数组,在其中就叫做elementData。
二、核心的方法:

1、增:

  1. add(E e); 添加集合元素到集合末尾。
  2. add(int index, E e); 在list集合指定下表位置添加元素。
  3. addAll(Collection<? extends E> c); 添加一个集合到当前集合的末尾(参数集合是元素类型是当前集合的子类或者当前约束类型)。
  4. addAll(int index, Collection<? extends E> c); 在指定下标位置,添加参数集合(注意约束集合的类型)

- boolean add(E);添加一个特定的元素到list的末尾。

public boolean add(E e) {
确定内部容量是否够了,size是数组中数据的个数,因为要添加一个元素,所以size+1;
需要先判断size+1 的这个个数数组能否放得下,就在这个方法中判断是否数组。length够用。
	ensureCapacityInternal(size + 1);
在数据的正确位置上放置元素e, 并且size++
	elementData[size++] = e;
	return true;
}
  • ensureCapacityInternal(xxx);确定内部容量的方法:
private void ensureCapacityInternal(int minCapacity){
	判断初始化的elementData是不是空数组
	if (elementData == EMPTY_ELEMENTDATA) {
	如果为空的话,minCapacity=size+1;空的数组没有长度就存放不下了,所以就将minCapacity变成默认大小10;
		minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
	}
		
	ensureExplicitCapacity(minCapacity);
}
  • ensureExplicitCapacity(xxx);
private void ensureExplicitCapacity(int minCapacity) {
	modCount++;
	if (minCapacity - elementData.length > 0) {
		grow(minCapacity);数组自动扩容
	}
}

1、minCapacity如果大于了实际elementData的长度,就说明elementData数组的长度不够用,就要增加elementData的length。
2、由于elementData初始化时是空的数组,那么第一次add的时候minCapacity=size+1;也就minCapacity=1,在上一个方法(确定内部容量ensureCapacityInternal)就会判断出是空的数组,就会给将minCapacity=10,到这一步为止,还没有改变elementData的大小。
3、elementData不是空的数组了,那么在add的时候,minCapacity=size+1;也就是minCapacity代表着elementData中增加之后的实际数据个数,拿着它判断elementData的length是否够用,如果length不够用,那么肯定要扩大容量,不然增加的这个元素就会溢出。

  • ArrayList核心grow(xxx)数组扩容方法:
private void grow(int minCapacity) {
	//1、将扩充前的elementData大小给oldCapacity
	int oldCapacity = elementData.length;
	//2、数组扩容为原来的1.5倍
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	//3、初始化elementData的大小
	if (newCapacity < minCapacity ) 
		newCapacity = minCapacity;
	//4、如果newCapacity超过了最大的容量限制,将能给的最大值给newCapacity
	if (newCapacity > MAX_ARRAY_SIZE)
		newCapacity = hugeCapacity(minCapacity);
	//5、新的容量大小已经确定,拷贝数组,改变数组容量
	elementData = Arrays.copyof(elementData, newCapacity);
}
  • hugeCapacity(); 赋值最大值
private static int hugeCapacity(int minCapacity) {
	if(minCapacity < 0)
		throw new OutOfMemoryError();
//如果minCapacity都大于MAX_ARRAY_SIZE,那么就Integer.MAX_VALUE返回,反之将MAX_ARRAY_SIZE返回。因为maxCapacity是三倍的minCapacity,可能扩充的太大了,就用minCapacity来判断了。
	return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

- void add(int index, E e); 在特定位置添加元素。

public void add(int index, E element) {
 //检查index也就是插入的位置是否合理。
        rangeCheckForAdd(index);
        ensureCapacityInternal(size + 1);  
//这个方法就是用来在插入元素之后,要将index之后的元素都往后移一位,
        System.arraycopy(elementData, index, elementData,index + 1, size - index);
//在目标位置上存放元素
        elementData[index] = element;
        size++;//size增加1
    }
  • rangeCheckForAdd(index)
private void rangeCheckForAdd(int index) {
	if (index > size || index < 0) //插入的位置不能大于size和小于0 
	 //报错越界异常
	  throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何忧何虑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值