ArrayList实现类

本文介绍了ArrayList类的逻辑结构、特点、存储方式以及与数组的区别。详细讲解了ArrayList的初始化、常见方法如add()、addAll()、get()等,并探讨了其扩容机制,包括无参和有参构造时的情况,最后给出了部分核心代码分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天,让我们一起走进ArrayList类,了解ArrayList类背后的故事

ArrayList类:

  1. 逻辑结构:首先我们要知道ArrayList类是实现了List接口,而
    List接口又继承了Collection接口。正是由于接口和继承的使用,使ArrayList类具有强大的能力和丰富的功能。

  2. 特点:①有序性允许重复

  3. 存储结构:内部利用了Object[]数组进行对元素的存储;

  4. 用处:ArrayList类对集合可以进行一系列操作(类似于Array类对数组进行一系列操作),并且由于存储结构的特点,相当于集合为加强版的数组(提供了比数组更多的操作)。

集合和数组的区别

1.集合比数组更为方便,并且提供了更多的操作。

2.数组长度固定,集合可以对长度进行扩容

3.数组运行速率较快,集合运行速率较慢(集合在数组外加了一系列逻辑相关的操作)

初始化(引用+创建)

1.非泛型

ArrayList list=new ArrayList()
list.add("小明");
list.add(23) ;       //可以添加任何类型值

可以创建任何Object子类元素集合。

2.泛型

ArrayList<String> list01=new ArrayList<String>();
list01.add("小飞");
//list01.add(23) ;     //不能为除String类型之外的任何类型

利用泛型创建集合对象,则类型为指定的泛型不能使用其他类型

注:当为无参构造时,传入的值为默认空数据,则不创建数组,只有进行一次添加元素时,才使传入值大于默认空数据,从而创建数组。

常见方法

  1. add()
    用处:向集合中添加指定元素
    参数:指定泛型的值
    返回:boolean类型的值
    注:默认添加的值都放于集合最后面

  2. addAll()
    用处:将一个集合的所有元素全部添加到另一个集合
    参数:Collection下的子类型
    返回:boolena类型的值

  3. get()
    用处:根据指定下标,得到该下标所对应的集合元素
    参数:int类型的index下标
    返回:集合中的元素

  4. size()
    用处:返回当前集合中元素的个数
    参数:无
    返回:int类型的值

  5. contains()
    用处:判断元素是否在该集合中
    参数:集合中的值
    返回:boolean类型的值,有返回true,否则返回false

  6. indexOf()
    用处:查找集合内指定元素的位置
    参数:集合中的指定元素
    返回:存在返回当前指定元素下标,不存在返回-1

  7. remove()
    用处:
    1.移除指定下标位置所对应的元素,并返回未移除之前的值
    2.移除指定元素
    参数:
    1.int类型指定下标位置
    2.指定元素
    返回:
    1.未移除之前的值
    2.成功移除:true ;否则:false

8.set()
用处:将指定下标位置的值修改为指定元素
参数:指定下标,指定元素
返回:未修改的原值

9.sort()
用处:给集合排序
参数:Comparator比较器接口实现类对象
返回:

10.to Array()
用处:将集合转换为数组
参数:无参
返回:Object[]数组

ArrayList类的扩容机制

注:要记着去抽一下源码,才能最好的去理解

抓住:grow(minCapacity)

问题1:若以无参构造创建对象,则内部Object[]数组是否创建?数组长度为多少?若是超出指定长度,则如何扩容?

问题2:若以有参构造创建对象,则内部Object[]数组长度不足以使用,则我该如何扩容,若是超出最大长度,我们该怎么办?

核心代码:

int newCapacity = oldCapacity + (oldCapacity >> 1);

//对旧容量增加到1.5倍(增加了0.5倍),存入newCapacity(新容量)

若为无参构造:
①确保数组长度够用,则使最小容量为size(数组中元素个数)+1(minCapacity);

②由于无参构造,则数组中为空值,和系统默认空数据相等,则系统扩容到10(此时数组长度为10),返回minCapacity。(该判断在无参构造中只进行第一次
下次判段,直接返回minCapacity;


有参无参构造的公共部分

③如果minCapacity<此时数组长度(element.length),则不需扩容
若是minCapacity>数组长度,则扩容 grow(minCapacity);

④ grow(minCapacity)

	令minCapacity先暂存	与oldCapacity(旧容量)

	int newCapacity = oldCapacity + (oldCapacity >> 1); 
	//对旧容量增加到1.5倍(增加了0.5倍),存入newCapacity(新容量)
	
	if (newCapacity - minCapacity < 0)
	  //若新容量还是小于要存入的元素个数,则令新容量为元素个数值									
		newCapacity = minCapacity;                                
	if (newCapacity - MAX_ARRAY_SIZE > 0)                            
	 //若新容量大于int的最大值-8,再进行扩容处理
		newCapacity = hugeCapacity(minCapacity);
	elementData = Arrays.copyOf(elementData, newCapacity);   
	//利用数组复制,得到新的数组长度


若是新的容量>Integer.MAX_VALUE-8
判断继续扩容
若元素个数大于Integer.MAX_VALUE(大于int范围则为负数),则抛出错误
若元素个数大于Integer.MAX_VALUE-8,小于Integer.MAX_VALUE, 则返回Integer.MAX_VALUE,否则返回Integer.MAX_VALUE-8

private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
//若元素个数大于int的最大值(大于int范围则为负数),则抛出错误
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
//若元素个数大于int的最大值-8,小于int最大值, 则返回int最大值,否则返回int最大值-8
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
}

阉割后的源代码,以及注释,希望对大家有用


public class ArrayList
{
	// 构造方法
	public ArrayList() {
			//由于为无参构造,则该元素为默认空数据
			this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
	}

	public ArrayList(int initialCapacity) {  //有参构造
		if (initialCapacity > 0) {
			this.elementData = new Object[initialCapacity];  //传入的长度大于0,则创建Object类的数组,长度为传入的值
		} else if (initialCapacity == 0) {
			this.elementData = EMPTY_ELEMENTDATA;       //传入长度为0,则不创建数组,使元素为默认空数据
		} else {
			throw new IllegalArgumentException("Illegal Capacity: "+              //当传入长度小于0,则抛出参数不合法异常
											   initialCapacity); 
		}
	}

	// 基础扩容方法

	// 添加元素
	public boolean add(E e) {
		// 按照元素个数+1,确认数组容量是否够用
		ensureCapacityInternal(size + 1);

		//当扩容完毕,将新元素添加到数组中,并使下标自加
		elementData[size++] = e;

		return true;
	}
	//判断是否需要
	private void ensureCapacityInternal(int minCapacity) {
		ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
	}
	//计算容量
	private static int calculateCapacity(Object[] elementData, int minCapacity) {
		if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {      //当为无参构造时,判断元素内容与默认空数据相等
			return Math.max(DEFAULT_CAPACITY, minCapacity);          //返回一个minCapacity=1,与DEFAULT_CAPACITY=10,选择一个最大值 10;
		}
		return minCapacity; //无参构造,第一次返回1,有参构造,返回传入的参数值+1
	}

	private void ensureExplicitCapacity(int minCapacity) {
		modCount++;

		// overflow-conscious code
		if (minCapacity - elementData.length > 0)         //如果传入的元素个数+1 > 数组长度
			grow(minCapacity);                           //对数组进行扩容
	}

	private void grow(int minCapacity) {
		// overflow-conscious code
		int oldCapacity = elementData.length;               //令数组长度先暂存与oldCapacity(旧容量)
		int newCapacity = oldCapacity + (oldCapacity >> 1);          //对旧容量增加到1.5倍(增加了0.5倍),存入newCapacity(新容量)
		if (newCapacity - minCapacity < 0)		             //若新容量还是小于要存入的元素个数,则令新容量为元素个数值									
			newCapacity = minCapacity;                                
		if (newCapacity - MAX_ARRAY_SIZE > 0)                             //若新容量大于int的最大值-8,再进行扩容处理
			newCapacity = hugeCapacity(minCapacity);
		elementData = Arrays.copyOf(elementData, newCapacity);   //利用数组复制,得到新的数组长度
	}

	 private static int hugeCapacity(int minCapacity) {                           
		if (minCapacity < 0) // overflow                                   //若元素个数大于int的最大值,则抛出错误
			throw new OutOfMemoryError();                
		return (minCapacity > MAX_ARRAY_SIZE) ?                  //若元素个数大于int的最大值-8,小于int最大值, 则返回int最大值,否则返回int最大值-8
			Integer.MAX_VALUE :
			MAX_ARRAY_SIZE;
	}
}

今天的内容就到这里,扩容机制,一定要结合源码进行分析,可以结合我的说的问题,去思考,学习。要是有什么错误的地方,请大家及时指正,谢谢!

让我们一起加油学习,做好自己,奥力给!!!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值