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. 8.1 Socket编程

    8.1 Socket编程 在很多底层网络应用开发者的眼里一切编程都是Socket,话虽然有点夸张,但却也几乎如此了,现在的网络编程几乎都是用Socket来编程.你想过这些情景么?我们每天打开浏览器浏览 ...

  2. erlang进程概述

    一.概述 与大多数的进程相反,Erlang中的并发很廉价,派生出一个进程就跟面向对象的语言中分配一个对象的开销差不多. 在启动一个复杂的运算时,启动运算.派生进程以及返回结果后,所有进程神奇的烟消云散 ...

  3. Centos7下安装MySql

    1.安装MariaDB 安装命令 yum -y install mariadb mariadb-server 安装完成MariaDB,首先启动MariaDB systemctl start maria ...

  4. ArcCore重构-Platform_Types.h实现辨析

    AUTOSAR定义了一系列PlatformTypes,如uint8/uint16/uint32等等基本类型. It contains all platform dependent types and ...

  5. PAT1081:Rational Sum

    1081. Rational Sum (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Given N ...

  6. virsh命令来创建虚拟机

    virsh命令来创建虚拟机步骤 (1)生成硬盘镜像文件: 格式:raw或qcow2 # qemu-img create -f raw fdisk.img 10G qemu-img convert re ...

  7. MySql中innodb存储引擎事务日志详解

    分析下MySql中innodb存储引擎是如何通过日志来实现事务的? Mysql会最大程度的使用缓存机制来提高数据库的访问效率,但是万一数据库发生断电,因为缓存的数据没有写入磁盘,导致缓存在内存中的数据 ...

  8. 深入解读Resnet

    残差网络的设计目的 随着网络深度增加,会出现一种退化问题,也就是当网络变得越来越深的时候,训练的准确率会趋于平缓,但是训练误差会变大,这明显不是过拟合造成的,因为过拟合是指网络的训练误差会不断变小,但 ...

  9. SVG的动态之美-搜狗地铁图重构散记

    搜狗地图发布了新版的移动端地铁图,改版初衷是为了用户交互体验的提升以及性能的改善.原版地铁图被用户吐槽最多的是pinch缩放不流畅.无过渡动画.拖拽边界不合理等等,大体上都是交互体验上的问题.实际上原 ...

  10. synchronized(this) 与synchronized(class) 之间的区别

    一.概念 synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机 ...