集合算是java中最常用的部分了,阅读该部分jdk代码可以让我们更加清楚的了解其实现原理,在使用时也能心中有数,有利于写出高质量的代码。
ArrayList
底层数组实现,初始长度10,超过长度后的自增实际是数组拷贝,拷贝用的System.copy()调用了本地方法,效率相对较高。
先看new ArrayList()

public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

可见,开始new ArrayList()的时候,数组长度其实是0,并不是10,是个空数组。

通过add(E e)方法进行查看:

public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确认容量,看下一个位置是不是没了
elementData[size++] = e; // 容量允许的话,放在当前元素的下一个位置
return true;
}

确认容量的方法:

private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // 如果当前数组为空
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); // 数组容量取 默认容量跟给定数据的较大者
}
ensureExplicitCapacity(minCapacity); // 确定明确的容量数值
}

  这里要了解的是两个变量的初始值:

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

  可以看到,elementData这个初始值是个null,但ArrayList创建的时候进行了赋值,因此这里有这个(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)判断。

  确定明确数值的方法:

private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 这个字段跟并发有关,稍后解释
// overflow-conscious code
if (minCapacity - elementData.length > 0) //给定值大于数组长度
grow(minCapacity);
}

  长度增长方法:

private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 新长度为原来的+原来的一半(初始10,变为15)
if (newCapacity - minCapacity < 0) // 加一半后长度还是不够,则用传递过来的数值(addAll来说,就是原长度+新集合长度)
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);
}

---------------------------------

解释:
按代码分析,新增一个元素,调用add方法,如果长度没超出,那么就在数组下个位置放置该元素,如果超出了,按照当前长度的一半增长(其实不是严格一半,比如长度是15的时候,下次增长长度为15(1111)右移一位为111=7)。新增的如果是一个集合,则根据原数组长度跟新集合的长度得出需要的最小容量,在grew方法中如果当前长度增长一半超过了计算出的容量,则用增长一半的长度,否则用计算的容量;而且,如果新容量到了十亿级别,则进行最大容量判断是否增长为Integer.MAX_VALUE。
这里有个内置的变量,private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;为什么-8呢,注释写的很清楚:
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
就是说有些虚拟机会预留出一定长度作为数组的一些头信息,所以数组最大长度达不到Integer的最大值2~32-1 = 2147483647(21亿..)左右,这个-8是为了避免内存溢出。
-------------------------------------------------------
一些其它的内容:
modCount只记录arraylist被修改次数,在每次添加修改删除的时候进行+1,参数名称也是modifyCount修改计数的意思;这个参数的作业就是在多线程并发的时候,由于arraylist不是线程安全的,在当前线程进行遍历等操作的时候,如果其它线程修改了程序,那么当前线程能检测到该参数发生变化,会报异常。

ArrayList代码分析的更多相关文章

  1. ArrayList的分析(转)

    一. ArrayList概述: ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存. ArrayList不是线程安全的,只能用在单线程环境 ...

  2. 学生管理系统开发代码分析笔记:jsp+java bean+servlet技术

    1 序言 学习java web的时候很渴望有一份完整的项目给我阅读,而网上的大部分项目拿过来都无法直接用,好不容易找到了一个学生管理系统也是漏洞百出.在此,我将边修改边学习这份代码,并且加上完全的注释 ...

  3. Hive metastore整体代码分析及详解

    从上一篇对Hive metastore表结构的简要分析中,我再根据数据设计的实体对象,再进行整个代码结构的总结.那么我们先打开metadata的目录,其目录结构: 可以看到,整个hivemeta的目录 ...

  4. java 导入Excel -- 套路及代码分析

    一.思路分析 1.我们要做导入,实际上也就是先文件上传,然后读取文件的数据. 2.我们要有一个导入的模板,因为我们导入的Excel列要和我们的数据字段匹配上,所以我们要给它来一个规定,也就是模板. 3 ...

  5. Android代码分析工具lint学习

    1 lint简介 1.1 概述 lint是随Android SDK自带的一个静态代码分析工具.它用来对Android工程的源文件进行检查,找出在正确性.安全.性能.可使用性.可访问性及国际化等方面可能 ...

  6. pmd静态代码分析

    在正式进入测试之前,进行一定的静态代码分析及code review对代码质量及系统提高是有帮助的,以上为数据证明 Pmd 它是一个基于静态规则集的Java源码分析器,它可以识别出潜在的如下问题:– 可 ...

  7. [Asp.net 5] DependencyInjection项目代码分析-目录

    微软DI文章系列如下所示: [Asp.net 5] DependencyInjection项目代码分析 [Asp.net 5] DependencyInjection项目代码分析2-Autofac [ ...

  8. [Asp.net 5] DependencyInjection项目代码分析4-微软的实现(5)(IEnumerable<>补充)

    Asp.net 5的依赖注入注入系列可以参考链接: [Asp.net 5] DependencyInjection项目代码分析-目录 我们在之前讲微软的实现时,对于OpenIEnumerableSer ...

  9. 完整全面的Java资源库(包括构建、操作、代码分析、编译器、数据库、社区等等)

    构建 这里搜集了用来构建应用程序的工具. Apache Maven:Maven使用声明进行构建并进行依赖管理,偏向于使用约定而不是配置进行构建.Maven优于Apache Ant.后者采用了一种过程化 ...

随机推荐

  1. Linux修改MySQL max_allowed_packet 值

    修改配置文件 vi /etc/my.cnf change "max_allowed_packet = 1M" to "max_allowed_packet = 32M&q ...

  2. PHP 中for循环的一个小小改进

    注意 : 1, $size这个值可以放在for循环中的第一个 ';' 前声明, 因为这个声明只会执行一次; 2, 第二个 ';' 中的内容, 会重复运行, 所以$i < $size 这个判断会每 ...

  3. C#利用phantomJS抓取AjAX动态页面

    在C#中,一般常用的请求方式,就是利用HttpWebRequest创建请求,返回报文.但是有时候遇到到动态加载的页面,却只能抓取部分内容,无法抓取到动态加载的内容. 如果遇到这种的话,推荐使用phan ...

  4. java eclipse导出可运行jar包(java服务)和导入

    java   eclipse导出可运行jar包(java服务)和导入 二.导出可运行包步骤: 1.选择要导出的项目:  2.右键项目-单击export:  3.选择导出类型:(Runnable JAR ...

  5. jzoj4915. 【GDOI2017模拟12.9】最长不下降子序列 (数列)

    题面 题解 调了好几个小时啊--话说我考试的时候脑子里到底在想啥-- 首先,这个数列肯定是有循环节的,而且循环节的长度\(T\)不会超过\(D\) 那么就可以把数列分成三份,\(L+S+R\),其中\ ...

  6. dedecms有缩略图则显示缩略图,没有则显示随机缩略图

    随着html5以及扁平化等新的设计概念的深入人心,缩略图功能则成了一般网页模版制作不可或缺的一个功能,dedecms默认的的缩略图调用标签[field:imglink/] 或者 [field:litp ...

  7. truts2标签-forEach标签

    <c:forEach begin="1" end="${obj.portnum}" step="1" varStatus=" ...

  8. STS(spring tool suite)修改默认编码

    安装STS后首先要做的修改默认编码: 1.windows--perferences--general--workspace,Text file encoding设置成utf-8 2.windows-- ...

  9. 利用DSB2017冠军开源代码为LUNA16生成mask

    代码地址:https://github.com/lfz/DSB2017 先展示下生成的mask与真实mask subset9 subset8 subset7 subset6 subset5 subse ...

  10. [Groovy]static typing

    一般想到Groovy是JVM上的动态语言,都不知道它还有Static Typeing的功能 import groovy.transform.TypeChecked void someMethod() ...