Java集合之ArrayList详解,大厂越来越注重基础了,建议收藏(1)

/**

  • Shared empty array instance used for empty instances.

*/

private static final Object[] EMPTY_ELEMENTDATA = {};

/**

  • Shared empty array instance used for default sized empty instances

*/

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

存储数组列表元素的数组缓冲区

/**

  • The array buffer into which the elements of the ArrayList are stored.

  • The capacity of the ArrayList is the length of this array buffer. Any

  • empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA

  • will be expanded to DEFAULT_CAPACITY when the first element is added.

*/

transient Object[] elementData; // non-private to simplify nested class access

数组中元素的大小,size是指elementData中实际有多少个元素,elementData.length为集合容量,表示集合当前最多可以容纳多少个元素

/**

  • The size of the ArrayList (the number of elements it contains).

*/

private int size;

modCount定义在父类AbstractList中。记录List的操作次数。主要使用在Iterator中,防止在迭代的过程中集合被修改

/**

  • The number of times this list has been structurally modified\

*/

protected transient int modCount = 0;

3、构造函数

3.1 无参构造函数

需要注意的是无参构造函数,给elementData赋值的是一个空的数组,在第一次添加元素的时候才把容量扩大为10,不要被注释给误导了。此处可见无参构造器是将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData

/**

  • Constructs an empty list with an initial capacity of ten.

*/

public ArrayList() {

this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

3.2 构造一个初始容量为initialCapacity的ArrayList

当initialCapacity>0,初始化一个大小为initialCapacity的Object数组,赋值给elementData;当initialCapacity==0,将EMPTY_ELEMENTDATA赋值给elementData;否则,抛出异常。

/**

  • Constructs an empty list with the specified initial capacity.

*/

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);

}

}

3.3 通过指定的Collection来初始化一个ArrayList

将Collection转为数组并且赋值给elementData,elementData.length赋值给size;如果size != 0,则判断elementData类型是否为Object[]类型,不是则做一次转换(注意此处其实是一个官方bug解决方案);如果size == 0则将EMPTY_ELEMENTDATA赋值给elementData,相当于new ArrayList(0)

public ArrayList(Collection<? extends E> c) {

elementData = c.toArray();

if ((size = elementData.length) != 0) {

// c.toArray might (incorrectly) not return Object[] (see 6260652)

if (elementData.getClass() != Object[].class)

elementData = Arrays.copyOf(elementData, size, Object[].class);

} else {

// replace with empty array.

this.elementData = EMPTY_ELEMENTDATA;

}

}

4、核心方法

4.1 add 操作

ensureCapacityInternal();

每次添加元素到集合中都会先确认集合容量的大小;

public boolean add(E e) {

ensureCapacityInternal(size + 1); // Increments modCount!!

elementData[size++] = e;

return true;

}

calculateCapacity();

判断elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA则取DEFAULT_CAPACITY和minCapacity的最大值,也就是10;此处验证了在第一次插入的时候才会给数组初始容量10;

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);

}

return minCapacity;

}

modCount++;

记录操作次数;

minCapacity - elementData.length > 0;

数组长度不够时对数组进行扩容,执行grow()函数的逻辑

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

// overflow-conscious code

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}

oldCapacity + (oldCapacity >> 1)

默认将数组的大小扩容到原来的1.5倍

newCapacity - minCapacity < 0

如果扩容后的容量不足,则将所需容量minCapacity赋值给newCapacity,扩容后数组大小就是申请的容量

newCapacity - MAX_ARRAY_SIZE > 0

如果扩容后的数组容量太大,超过了Integer.MAX_VALUE - 8的大小,则数组的大小为hugeCapacity(),(minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;

private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

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

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

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);

}

private static int hugeCapacity(int minCapacity) {

if (minCapacity < 0) // overflow

throw new OutOfMemoryError();

return (minCapacity > MAX_ARRAY_SIZE) ?

Integer.MAX_VALUE :

MAX_ARRAY_SIZE;

}

其余add()方法大同小异

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++;

}

public boolean addAll(Collection<? extends E> c) {

Object[] a = c.toArray();

int numNew = a.length;

ensureCapacityInternal(size + numNew); // Increments modCount

System.arraycopy(a, 0, elementData, size, numNew);

size += numNew;

return numNew != 0;

}

public boolean addAll(int index, Collection<? extends E> c) {

rangeCheckForAdd(index);

Object[] a = c.toArray();

int numNew = a.length;

ensureCapacityInternal(size + numNew); // Increments modCount

int numMoved = size - index;

if (numMoved > 0)

System.arraycopy(elementData, index, elementData, index + numNew, numMoved);

System.arraycopy(a, 0, elementData, index, numNew);

size += numNew;

return numNew != 0;

}

4.2 remove 操作

rangeCheck(index);

检查index是否合法,当index >= size时,抛出IndexOutOfBoundsException异常;

modCount++;

记录集合的操作次数;

E oldValue = elementData(index);

取出移除元素,用于放回给方法调用者;

if (numMoved > 0)

判断当前删除的集合元素是否时数组的最后一个元素,如果不是最后一个元素,则调用System.arraycopy()方法做一次数组拷贝;如果移除的元素是最后一个元素或者在数组复制结束之后,将数组的最后一个元素置为null,等待GC垃圾回收;–size数组的大小减一;

public E remove(int index) {

rangeCheck(index);

modCount++;

E oldValue = elementData(index);

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index, numMoved);

elementData[–size] = null; // clear to let GC do its work

return oldValue;

}

4.3 get 操作

rangeCheck(index);

检查index是否合法,当index >= size时,抛出IndexOutOfBoundsException异常;

elementData(index);

由于ArrayList的底层是由数组实现的,所有获取元素直接调用数组的随机访问即可;

public E get(int index) {

rangeCheck(index);

return elementData(index);

}

5、Iterator

5.1 前言

Java开发初级工程师在使用for遍历集合的时候,由于使用不正确的API方法对集合进行remove()操作,经常会抛出java.util.ConcurrentModificationException,因此我们来从源码的层面仔细的探究一下为什么会产生ConcurrentModificationException以及如何解决这个异常!foreach循环又称增强for循环,是jdk1.5为了简化数组或者和容器遍历而产生,foreach循环的适用范围:对于任何实现了Iterable接口的容器都可以使用foreach循环。foreach语法的冒号后面可以有两种类型,一种是数组类型;一种是实现了Iterable接口的类,因此在使用foreach循环遍历ArrayList的时候,可以看作就是在使用List的迭代器进行遍历

如下代码,foreach遍历list集合时,调用list.remove(s)方法,控制台输出了预期ConcurrentModificationException异常

在这里插入图片描述

5.2 ArrayList中Iterator

本质上返回的是一个Itr实例化对象

public Iterator iterator() {

return new Itr();

}

ArrayList定义了一个Itr内部类实现了Iterator接口,Itr内部有三个属性。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

我的面试宝典:一线互联网大厂Java核心面试题库

以下是我个人的一些做法,希望可以给各位提供一些帮助:

整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

image

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

image

还有源码相关的阅读学习

image

片转存中…(img-Jpfcnb7z-1712091551238)]

我的面试宝典:一线互联网大厂Java核心面试题库

以下是我个人的一些做法,希望可以给各位提供一些帮助:

整理了很长一段时间,拿来复习面试刷题非常合适,其中包括了Java基础、异常、集合、并发编程、JVM、Spring全家桶、MyBatis、Redis、数据库、中间件MQ、Dubbo、Linux、Tomcat、ZooKeeper、Netty等等,且还会持续的更新…可star一下!

[外链图片转存中…(img-F8GLH7NY-1712091551239)]

283页的Java进阶核心pdf文档

Java部分:Java基础,集合,并发,多线程,JVM,设计模式

数据结构算法:Java算法,数据结构

开源框架部分:Spring,MyBatis,MVC,netty,tomcat

分布式部分:架构设计,Redis缓存,Zookeeper,kafka,RabbitMQ,负载均衡等

微服务部分:SpringBoot,SpringCloud,Dubbo,Docker

[外链图片转存中…(img-xymYsrQ5-1712091551239)]

还有源码相关的阅读学习

[外链图片转存中…(img-axM4uHwg-1712091551239)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值