ArrayList是Java开发中经常用到的集合类,它是List接口的实现类,具有很高的查询性能,但不是线程安全的。本文主要讲述了ArrayList的add(E e)方法及该方法中涉及到的容量扩容技术。

  • 本文大纲

1.ArrayList底层数据结构

2.add(E e)方法流程概览

3.add(E e)方法与扩容源码分析

说明:本文对ArrayList的源码分析是基于JDK8。

  • 正文

1.ArrayList底层数据结构

ArrayList的底层数据结构为一个Object数组,对应到源码中是:

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

2.add(E e)方法流程概览

add(E e)方法的大致流程:

3.add(E e)方法与扩容源码分析

接着再看一下源码:

public boolean add(E e) {
  // 确保数组有足够的空间来存储对象e
  ensureCapacityInternal(size + 1); // Increments modCount!!
  // 将对象e存放到数组的末尾
  elementData[size++] = e;
  return true;
}
ensureCapacityInternal方法主要是确保elementData数组有足够的空间来存储待添加的元素:
// 参数minCapacity是add(E e)方法中调用ensureCapacityInternal方法时传入的size + 1的值
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}

参数minCapacity是为了存放这个元素elementData数组所需要的最小的大小。比如,现在一个数组中存放了10个元素,再次向该数组存放一个元素时,那么这个minCapacity的值就是size + 1,即10 + 1 = 11。

private void ensureExplicitCapacity(int minCapacity) {
modCount++; // overflow-conscious code
if (minCapacity - elementData.length > 0)
     // 存放新元素所需的最小容量大于elementData数组的长度
grow(minCapacity);
}

如果存放新元素所需的最小容量大于elementData数组的长度,即当前数组的容量不足,不能再存放新的元素,那么将基于elementData数组进行扩容。

private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); // 计算新数组的容量,新数组的容量为原数组容量的1.5倍数。>>是移位运算符,oldCapacity >> 1表示oldCapacity除以2
if (newCapacity - minCapacity < 0) // 针对当创建的ArrayList的容量大小为1时能够进行扩容(下面将详细分析)
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); // 进行数组拷贝,并将新产生的数组赋值给elementData
}

当我们在new ArrayList的时候,如果指定ArrayList的容量大小为1(比如,new ArrayList<>(1)),再进行add(E e)操作,在执行代码int newCapacity = oldCapacity + (oldCapacity >> 1)时,newCapacity的值为1,newCapacity与oldCapacity的值都为1,这样其实并没有进行扩容。if (newCapacity - minCapacity < 0)就是为避免这种情况,当newCapacity(此例中为1)的值小于minCapacity(此例中为2)时,就把minCapacity的值赋给newCapacity。

ArrayList的add(E e)方法与扩容的更多相关文章

  1. ArrayList的add方法实现

    ArrayList的底层是由数组实现,所以所有的操作都是围绕数组展开,要想理解add方法,就得先了解数组的增加,所以我们先实现一个数组的add,数组的添加可以从尾部增加或者其他位置插入, 如果在数组的 ...

  2. Java集合详解1:一文读懂ArrayList,Vector与Stack使用方法和实现原理

    本文非常详尽地介绍了Java中的三个集合类 ArrayList,Vector与Stack <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整 ...

  3. ArrayList和HashSet的Contains()方法(转)

    来源: ArrayList和HashSet的Contains()方法 笔试题: package com.champion.test.exam; import java.util.ArrayList; ...

  4. Java-集合(没做出来)第四题 (List)写一个函数reverseList,该函数能够接受一个List,然后把该List 倒序排列。 例如: List list = new ArrayList(); list.add(“Hello”); list.add(“World”); list.add(“Learn”); //此时list 为Hello World Learn reverseL

    没做出来 第四题 (List)写一个函数reverseList,该函数能够接受一个List,然后把该List 倒序排列. 例如: List list = new ArrayList(); list.a ...

  5. java中把list列表转为arrayList以及arraylist数组截取的简单方法

    java中把list列表转为arrayList以及arraylist数组截取的简单方法 package xiaobai; import java.util.ArrayList; import java ...

  6. Java学习笔记27(集合框架一:ArrayList回顾、Collection接口方法)

    集合:集合是java中提供的一种容器,可以用来存储多个数据 集合和数组的区别: 1.数组的长度是固定的,集合的长度是可变的 2.集合中存储的元素必须是引用类型数据 对ArrayList集合的回顾 示例 ...

  7. Java进阶(二十四)Java List集合add与set方法原理简介

    Java List集合add与set方法原理简介 add方法 add方法用于向集合列表中添加对象. 语法1 用于在列表的尾部插入指定元素.如果List集合对象由于调用add方法而发生更改,则返回 tr ...

  8. java学习笔记20(Arraylist复习,Collection接口方法,迭代器,增强型for循环)

    集合:集合是Java提供的一种容器,可以用来存储多个数据: 集合与数组的区别:集合的长度是可变的,数组的长度是固定的 集合中存储的数据必须是引用类型数据: ArrayList回顾: public cl ...

  9. C#集合中的Add与AddRange方法

    C#.NET的集合主要位于System.Collections和System.Collections.Generic(泛型)这两个namespace中. 1.System.Collections 比如 ...

随机推荐

  1. nginx 反向代理,支持跨域,前后分离

    前端开发往往涉及到跨域问题,其中解决方案很多: 1.jsonp 需要目标服务器配合一个callback函数. 2.window.name+iframe 需要目标服务器响应window.name. 3. ...

  2. PermutationTwo

    Description: Given a collection of numbers that might contain duplicates, return all possible unique ...

  3. 获取linux帮助命令

    命令的分类 linux的命令分为内部命令和外部命令.  内部命令指的是shell程序自带的命令,是shell程序的一部分,这些命令由shell程序识别并在shell程序内部完成运行,通常在linux系 ...

  4. tomcat 构建问题记录

    mvng构建程序包com.sun.image.codec.jpeg不存在------->缺少serlet的jar包 MasterSlaveRoutingDataSource不是抽象的, 并且未覆 ...

  5. 进阶-MongoDB 知识梳理

    MongoDB 一.MongoDB简介 MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种.它在许多场景下可用于替代传统的关系型数据库或键/值存储方式.Mo ...

  6. vh、vw、vmin、vmax 知多少

    介绍一些 CSS3 新增的单位,平时可能用的比较少,但是由于单位的特性,在一些特殊场合会有妙用. vw and vh 1vw 等于1/100的视口宽度 (Viewport Width) 1vh 等于1 ...

  7. 高质量的内容是SEO的关键

    内容是最有效的SEO策略,但也是最难执行的 正确的目录对SEO(搜索引擎优化:search engine optimization)关乎重大.根据Ascend2在2014年4月对全球营销专业人士做的调 ...

  8. 聊聊 Spring Boot 2.x 那些事儿

    本文目录: 即将的 Spring 2.0 - Spring 2.0 是什么 - 开发环境和 IDE - 使用 Spring Initializr 快速入门 Starter 组件 - Web:REST ...

  9. JSONUtils.toJSONString的一个坑

    JSONUtils.toJSONString(null); //返回一个为"null"的字符串 这样会导致一个结果就是StringUtils.isBlank判断后,会为false ...

  10. python实现邮件的发送

    一.163邮箱设置 进入163邮箱,点击设置中的pop3/smtp/imap 开启smtp服务,如果没有开启,点击设置,手机号验证后勾选开启即可,开启后图如下: 主要用到的就是smtp服务器:smtp ...