java 容器(collection)--ArrayList 常用方法分析 源码分析
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 常用方法分析 源码分析的更多相关文章
- List中的ArrayList和LinkedList源码分析
List是在面试中经常会问的一点,在我们面试中知道的仅仅是List是单列集合Collection下的一个实现类, List的实现接口又有几个,一个是ArrayList,还有一个是LinkedLis ...
- ArrayList详解-源码分析
ArrayList详解-源码分析 1. 概述 在平时的开发中,用到最多的集合应该就是ArrayList了,本篇文章将结合源代码来学习ArrayList. ArrayList是基于数组实现的集合列表 支 ...
- JAVA ArrayList集合底层源码分析
目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...
- Java入门系列之集合LinkedList源码分析(九)
前言 上一节我们手写实现了单链表和双链表,本节我们来看看源码是如何实现的并且对比手动实现有哪些可优化的地方. LinkedList源码分析 通过上一节我们对双链表原理的讲解,同时我们对照如下图也可知道 ...
- Java -- 基于JDK1.8的LinkedList源码分析
1,上周末我们一起分析了ArrayList的源码并进行了一些总结,因为最近在看Collection这一块的东西,下面的图也是大致的总结了Collection里面重要的接口和类,如果没有意外的话后面基本 ...
- 2.8.2 并发下的ArrayList,以及源码分析
package 第二章.并发下的ArrayList; import java.util.ArrayList;import java.util.List; /** * Created by zzq on ...
- 《Java Spring框架》Spring IOC 源码分析
1.下载源码 源码部署:https://www.cnblogs.com/jssj/p/11631881.html 并不强求,最好是有源码(方便理解和查问题). 2. 创建子项目 Spring项目中创建 ...
- Java ThreadPoolExecutor线程池原理及源码分析
一.源码分析(基于JDK1.6) ThreadExecutorPool是使用最多的线程池组件,了解它的原始资料最好是从从设计者(Doug Lea)的口中知道它的来龙去脉.在Jdk1.6中,Thread ...
- 设计模式(十七)——迭代器模式(ArrayList 集合应用源码分析)
1 看一个具体的需求 编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系.如图: 2 传统的设计方案(类图) 3 传统的方式的问题分析 ...
- java集合【13】——— Stack源码分析走一波
前言 集合源码分析系列:Java集合源码分析 前面已经把Vector,ArrayList,LinkedList分析完了,本来是想开始Map这一块,但是看了下面这个接口设计框架图:整个接口框架关系如下( ...
随机推荐
- 数塔(杭电oj2084)
Problem Description 在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大 ...
- sql 数据库操作语句 不带select
MySQL数据操作语句 1.总纲 DDL -数据定义语句** create/drop/alter ** create: 创建 drop:删除 alter:修改 DML -数据操作语句 ** inser ...
- 《java编程思想》 初始化与清理
1.初始化与清理的重要性: 1.许多C程序的错误都源于程序员忘记初始化变量,特别是使用程序库时,如果不知道如何初始化库的构件更容易出错 2.当使用完一个元素时,这个元素就不会有什么影响了,所以很容易就 ...
- .net core系统跨平台部署手册
前言 .net core跨平台版本基于.net core 3.1 SDK开发,剥离原来的基于MS Office进行文档转换功能的模块,使用基于开源跨平台的LibreOffice进行文档转换的模块.以此 ...
- Java 程序该怎么优化?(命令篇)
灵魂拷问,JDK 提供的命令,除了 java.javac,你还用过哪些命令呢? 灵魂再拷问,若你写的 Java 程序,出现了性能问题,该怎么去排查呢? Java 作为编程语言中的战斗机,JDK 默认已 ...
- 人生苦短,学用python
1. 我为什么开始学着用 python 啦? 扯扯网上疯传的一组图片.网上流传<人工智能实验教材>的图片,为幼儿园的小朋友们量身打造的实验教材,可谓是火了.甚至有网友调侃道:pytho ...
- 解决 node-sass 安装失败
在项目下新建.npmrc文件内容如下: sass_binary_site=https://npm.taobao.org/mirrors/node-sass/ phantomjs_cdnurl=http ...
- Kubernetes Pod钩子
目录 1.Pod容器钩子最终目的 2.何为Pod容器钩子 3.基于PostStart演示 4.基于PreStop演示 5.优雅停止Java应用 1.Pod容器钩子最终目的 之前在生产环境中使用dubb ...
- Java数组的声明与创建
今天在刷Java题的时候,写惯了C++发现忘记了Java数组的操作,遂把以前写的文章发出来温习一下. 首先,数组有几种创建方式? Java程序中的数组必须先进行初始化才可以使用,所谓初始化,就是为数组 ...
- 数据库学习 day2 检索数据
上一节我们介绍了什么是数据库,以及一些基本的数据库术语 这一课介绍使用SELECT语句从表中检索一个或多个数据列. 关键字(Keyword) 作为SQL组成部分的保留字.关键字不能用作表和列的名字(类 ...