ArrayList 介绍

打开jdk源码看看官方文档的介绍



粗糙的翻译下大致意思是:

List接口的可调整大小的数组实现。实现了所有可选的列表操作,并允许所有元素,包括 null 。除了实现List接口之外,这个类提供了操作数组大小的方法。

ArrayList定义的属性

 /**
* 默认容量大小10
*/
private static final int DEFAULT_CAPACITY = 10; /**
* 空构造器调用
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /**
* 缓冲区
*/
transient Object[] elementData; // non-private to simplify nested class access /**
* 元素个数
*/
private int size;

无参构造器

  /**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

这个相当于创建一个空数组:

this.elementData={};

有参构造器

/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
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);
}
}

他的健壮性比较好,我们按正常思维,只看第一个 initialCapacity > 0 的 if 分支:

相当于创建一个长度为 20 的数值:

this.elementData=new Object[20];

添加方法 add(Object obj)

public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}

这个代码技术含量挺高,不愧是老司机写的

ensureCapacityInternal(size + 1); 用来 检测空间容量是否够用(看下一个方法)

elementData[size++] = e; 就是添加元素相当于:

elementData[size]=e; size++;

检测空间容量是否够用

 private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

这个方法首先会在内部调用calculateCapacity(elementData, minCapacity) 计算容量:

private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}

当我们在新建一个ArrayList 对象上添加元素时:

Math.max(DEFAULT_CAPACITY, minCapacity); 相当于:

Math.max(10,1);

到这里容量计算完了,然后回去执行:

 private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}

由于是第一次添加,if 条件相当于:

if( 10 - 0 > 0)

结果为true,会执行if语句块

grow(minCapacity); 执行的就是扩容方法。

扩容方法

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

我们是第一次添加,以上代码实际执行的就是:

int oldCapactiy=0;

int newCapacity=0+0>>1 结果为0

如果 0-10<0 为 true

newCapacity=10;

数组拷贝 elementData的长度就是 10

最后回到:

public boolean add(E e) {

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

elementData[size++] = e;

return true;

}

结果就是:

elementData[0] = e;

size++;

接下来看下add 的重载方法

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

rangeCheckForAdd(index);是下标越界检测,我们先不看,下一行代码:

ensureCapacityInternal(size + 1);跟之前的默认位置天机一样先检测数组的空间容量。

关键是再往下一行代码;

执行的结果是把要插入位置开始到结束的所有元素往后挪一个位置,然后把空出的位置赋值为传入有的参数,同时把元素个数+1;

现在ArrayList对象的容量是10了,当我么一直做添加操作,容量满了会怎么样呢?

其实不管我们怎么添加,都会执行ensureCapacityInternal(size + 1) 来检测容量,而ensureCapacityInternal(size + 1)又会调用calculateCapacity(elementData, minCapacity)直到

ensureExplicitCapacity(int minCapacity)方法中的if语句成立时,执行

grow(minCapacity);进行扩容:

比如我们加到第11个元素时:

grow(minCapacity)方法中的

oldCapacity + (oldCapacity >> 1);返回15;

那么ArrayList的容量就增加到15了;

继续增加还是一样的操作。

至此,我们已经对ArrayList 创建,添加,扩容有了一定了解。

那么剩下的一些方法就是数组的操作了,很好理解。

ArrayList的其他方法

get(int index)根据索引获取元素对象

public E get(int index) {
rangeCheck(index);
//调用了elementData()的方法
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
//根据索引取出数组中索引对象
return (E) elementData[index];
}

size()

  public int size() {
// 返回集合记录的元素个数
return size;
}

isEmpty()

public boolean isEmpty() {
// 这个太简单了,不必多说
return size == 0;
}

set(int index, Object obj)

public E set(int index, E element) {
rangeCheck(index); E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}

就是数组操作,返回替换掉的元素

remove(int index)

 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; // 将最后一个位置设置为null return oldValue;
}

类似于前面的指定位置添加,返回原始元素对象

clear()

public void clear() {
modCount++; // clear to let GC do its work
for (int i = 0; i < size; i++)
elementData[i] = null; size = 0;
}

循环遍历,所有 索引位置的元素赋值null,并把元素个数设置为0;

水平有限,先写到这了。

java 容器(collection)--ArrayList 常用方法分析 源码分析的更多相关文章

  1. List中的ArrayList和LinkedList源码分析

    ​ List是在面试中经常会问的一点,在我们面试中知道的仅仅是List是单列集合Collection下的一个实现类, List的实现接口又有几个,一个是ArrayList,还有一个是LinkedLis ...

  2. ArrayList详解-源码分析

    ArrayList详解-源码分析 1. 概述 在平时的开发中,用到最多的集合应该就是ArrayList了,本篇文章将结合源代码来学习ArrayList. ArrayList是基于数组实现的集合列表 支 ...

  3. JAVA ArrayList集合底层源码分析

    目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...

  4. Java入门系列之集合LinkedList源码分析(九)

    前言 上一节我们手写实现了单链表和双链表,本节我们来看看源码是如何实现的并且对比手动实现有哪些可优化的地方. LinkedList源码分析 通过上一节我们对双链表原理的讲解,同时我们对照如下图也可知道 ...

  5. Java -- 基于JDK1.8的LinkedList源码分析

    1,上周末我们一起分析了ArrayList的源码并进行了一些总结,因为最近在看Collection这一块的东西,下面的图也是大致的总结了Collection里面重要的接口和类,如果没有意外的话后面基本 ...

  6. 2.8.2 并发下的ArrayList,以及源码分析

    package 第二章.并发下的ArrayList; import java.util.ArrayList;import java.util.List; /** * Created by zzq on ...

  7. 《Java Spring框架》Spring IOC 源码分析

    1.下载源码 源码部署:https://www.cnblogs.com/jssj/p/11631881.html 并不强求,最好是有源码(方便理解和查问题). 2. 创建子项目 Spring项目中创建 ...

  8. Java ThreadPoolExecutor线程池原理及源码分析

    一.源码分析(基于JDK1.6) ThreadExecutorPool是使用最多的线程池组件,了解它的原始资料最好是从从设计者(Doug Lea)的口中知道它的来龙去脉.在Jdk1.6中,Thread ...

  9. 设计模式(十七)——迭代器模式(ArrayList 集合应用源码分析)

    1 看一个具体的需求 编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系.如图: 2 传统的设计方案(类图) 3 传统的方式的问题分析 ...

  10. java集合【13】——— Stack源码分析走一波

    前言 集合源码分析系列:Java集合源码分析 前面已经把Vector,ArrayList,LinkedList分析完了,本来是想开始Map这一块,但是看了下面这个接口设计框架图:整个接口框架关系如下( ...

随机推荐

  1. nginx负载均衡例子

    upstream demo { ip_hash;//客户连接后, 一直用这个IP,直到会话结束,否则,动态程序可能会在换IP后出错 server 192.168.1.1:80 weight=5 | d ...

  2. spring ioc源码简析

    ClassPathXmlApplicationContext 首先我们先从平时启动spring常用的ClassPathXmlApplicationContext开始解析 ApplicationCont ...

  3. Linux环境下部署项目时的步骤和一些要注意的点

    SQL的导出和导入 sql的导出 首先选中要导出的数据库 然后点击左下角的administration选项,进入导出界面. 点击Data Export 然后勾选图中的几个选项即可导出一个sql,如果需 ...

  4. RbbitMQ详解

    高性能消息队列RabbitMQ 1.为什么要使用mq 主要解决应用解耦,流量削峰,异步消息,实现高性能,可升缩,最终一致性的架构. 2.activeMq的通讯模式 基于队列(点对点)与发布订阅(有多个 ...

  5. 【Net】ABP框架学习之正面硬钢

    前言 本文介绍另一种学习ABP框架的方法,该方法为正面硬钢学习法... 我们不去官网下载模板,直接引用DLL,直接使用. WebApi项目创建 首先创建一个WebApi项目,结构如下. 然后Nuget ...

  6. JAVA WEB随笔

    servlet生命周期: 1.构造器(单利)2.init(单例)3.service(多例,每次请求都会执行)4.销毁方法destroyservlet解析客户端请求流程:1.web客户端向servlet ...

  7. 分派pie(二分法)

    2.问题描述 我的生日要到了!根据习俗,我需要将一些派分给大家.我有N个不同口味.不同大小的派.有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块拼成:可以是一整个派 ...

  8. JSP+SSH+Mysql+C3P0实现的传智播客网上商城

    项目简介 项目来源于:https://gitee.com/2121/shop 本系统是传智播客授课时的开发案例,基于JSP+SSH+Mysql的简单网上商城.在当代开发中,SSH的使用已经逐渐被SSM ...

  9. es6的箭头函数和es5的function函数区别

    一.es6的箭头函数es6箭头函数内部没有this,使用时会上朔寻找最近的this不可以做构造函数,不能使用new命令,因为没有this函数体内没有arguments,可以使用rest参数代替不能用y ...

  10. 手动搭建I/O网络通信框架2:Socket和ServerSocket入门实战,实现单聊

    第一章:手动搭建I/O网络通信框架1:Socket和ServerSocket入门实战,实现单聊 在第一章中运用Socket和ServerSocket简单的实现了网络通信.这一章,利用BIO编程模型进行 ...