JDK1.8中ArrayList是如何扩容的

ArrayList简介:

ArrayList实现了List接口它是一个可调整大小的数组可以用来存放各种形式的数据。并提供了包括CRUD在内的多种方法可以对数据进行操作但是它不是线程安全的,外ArrayList按照插入的顺序来存放数据。

在讲扩容机制之前,我们需要了解一下ArrayList中最主要的几个变量:

private static final int DEFAULT_CAPACITY = 10;//数组默认初始容量

private static final Object[] EMPTY_ELEMENTDATA = {};//定义一个空的数组实例以供其他需要用到空数组的地方调用 

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//定义一个空数组,跟前面的区别就是这个空数组是用来判断ArrayList第一添加数据的时候要扩容多少。默认的构造器情况下返回这个空数组 

transient Object[] elementData;//数据存的地方它的容量就是这个数组的长度,同时只要是使用默认构造器(DEFAULTCAPACITY_EMPTY_ELEMENTDATA )第一次添加数据的时候容量扩容为DEFAULT_CAPACITY = 10 

private int size;//当前数组的长度

本题的所有的讲解都是基于JDK8

这道题考察了ArrayList的构造器和对扩容机制的了解,本篇博客基于此出发讲解ArrayList的扩容机制

想要做出这道题必须了解ArrayList的构造函数,ArrayList的构造函数总共有三个:

  • ArrayList()构造一个空的数组。JDK7中构造一个初始容量为10的空列表但是JDK8中只是构造一个空的数组
  • ArrayList(Collection<? extends E> c)构造一个包含指定 collection 的元素的数组,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
  • ArrayList(int initialCapacity)构造一个具有指定初始容量的空数组。

我们重点来看这两个ArrayList(int initialCapacity)ArrayList()构造函数

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

初始化一个空数组,这是JDK8不同于之前版本的地方

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那么就声明一个和形参一样大小的数组。了解到这里似乎这道题的正确答案也出来了即选择A,并没有发生扩容

但是作为一名合格的程序员要有探索精神,题目提到了扩容,既然ArrayList底层是一个数组,那么就肯定会满,什么时候发生扩容呢?

//1.add方法为添加元素在数组末尾
public boolean add(E e) {
    //确保数组容量 size指向数组的末尾
    ensureCapacityInternal(size + 1);
    //在完成添加之前要确保数组长度足够
    elementData[size++] = e;
    return true;
}
//3.elementData为ArrayList底层维护的数组,minCapacity为此时数组的大小
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //如果数组为初始化的值,就初始化数组容量为10(空参的构造方法下首次添加)
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
//2.minCapacity表示此时数组的大小
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//4.minCapacity表示此时数组的大小
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    //如果此时数组容量的大小不够就扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

源码读到这里,我们明白了,当我们每次向ArrayList添加元素的时候,都会首先确保数组容量够放下元素如果不够就会 grow(minCapacity)调用扩容函数,那么秉承着探索的精神,原本大小的数组扩容之后变成多大了呢?还得继续看源码

//扩容源码
private void grow(int minCapacity) {
    //获取当前数组的长度
    int oldCapacity = elementData.length;
    //>>右移相当于整除2,新容量相当于就旧容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果扩容后的容量还不够那么就以需要的容量为新容量
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //如果新容量已经超过最大容量了,那么就直接使用最大容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    //讲新容量的数组拷贝
    elementData = Arrays.copyOf(elementData, newCapacity);
}

源码大致读完后,我们明白了ArrayList的自动扩容机制,每次新添加元素的时候都会判断是否能够容下,如果不够就会发生扩容,扩容的大小为原大小的1.5倍数,明白这些以后让我们看看下面这段程序扩容了几次呢??容量是多少呢?

ArrayList<Integer> arrayList = new ArrayList<Integer>(20);
for(int i=1;i<=50;i++) {
     arrayList.add(i);
}

前20次添加不会发生扩容,当21元素添加时数组容量从20扩容到30,当添加31元素时数组容量从30扩容到45,当添加46元素时数组容量从45扩容到67

到此这篇关于JDK1.8中ArrayList是如何扩容的的文章就介绍到这了,更多相关JDK1.8 ArrayList扩容内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 对Java ArrayList的自动扩容机制示例讲解

    注意: 不同的JDK版本的扩容机制可能有差异 实验环境:JDK1.8 扩容机制: 当向ArrayList中添加元素的时候,ArrayList如果要满足新元素的存储超过ArrayList存储新元素前的存储能力,ArrayList会增强自身的存储能力,已达到存储新元素的要求 ArrayList:本质通过内部维护的数组对象进行数据存储 ①:分析ArrayList的add(E)方法 public boolean add(E e) { ensureCapacityInternal(size + 1); /

  • 在java中ArrayList集合底层的扩容原理

    第一章 前言概述 第01节 概述 底层说明 ArrayList是List的实现类,它的底层是用Object数组存储,线程不安全 后期应用 适合用于频繁的查询工作,因为底层是数组,可以快速通过数组下标进行查找 第02节 区别 区别方向 ArrayList集合 LinkedList集合 线程安全 不安全 不安全 底层原理 Object类型数组 双向链表 随机访问 支持(实现 RandomAccess接口) 不支持 内存占用 ArrayList 浪费空间, 底层是数组,末尾预留一部分容量空间 Link

  • Java ArrayList扩容问题实例详解

    本文研究的主要是Java ArrayList扩容问题实例详解的相关内容,具体介绍如下. 首先我们需要知道ArrayList里面的实质的其实是一个Object类型的数组,ArrayList的扩容问题其实就是这个Object类型的数组的扩容问题. transient Object[] elementData; 一.创建时,ArrayList的容量分配 创建一个ArrayList有三种情况 1.默认大小创建(默认为0) ArrayList al = new ArrayList(); 创建完成之后,al

  • 详解ArrayList的扩容机制

    目录 一.ArrayList 了解过吗?它是啥?有啥用? 二.ArrayList 如何指定底层数组大小的 三.数组的大小一旦被规定就无法改变 四.ArrayList 具体是怎么添加数据的 五.ArrayList 又是如何删除数据的呢 六.ArrayList 是线程安全的吗?不安全的表现 七.为什么线程不安全还要用它呢 一.ArrayList 了解过吗?它是啥?有啥用? 众所周知,Java 集合框架拥有两大接口 Collection 和 Map,其中,Collection 麾下三生子 List.S

  • 聊一聊jdk1.8中的ArrayList 底层数组是如何扩容的

    一.结论先行 ArrayList在JDK1.8与JDK1.7底层区别 JDK1.7:ArrayList像饿汉式,直接创建一个初始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍 JDK1.8:ArrayList像懒汉式,一开始创建一个长度为0的数组,当添加第一个元素时再创建一个始容量为10的数组,当数组的长度不能容下所添加的内容时候,数组会扩容至原大小的1.5倍 二.JDK1.8 ArrayList源码分析 1.ArrayList 属性 /** * 默认容量的

  • Java中的ArrayList容量及扩容方式

    目录 查看JDK1.8 ArrayList的源代码 1.默认初始容量为10 2.最大容量为 Integer.MAX_VALUE - 8 3.扩容方式: Java ArrayList() 扩容原理 先看下 ArrayList 的属性以及构造方法,这个比较重要 上看说的是初始化场景,下面看一下其他场景,也是相当简单 结论 查看JDK1.8 ArrayList的源代码 1.默认初始容量为10 /** * Default initial capacity. */ private static final

  • Java使用数组实现ArrayList的动态扩容的方法

    提到数组大家肯定不会陌生,但我们也知道数组有个缺点就是在创建时就确定了长度,之后就不能更改长度.所以Java官方向我们提供了ArrayList这个可变长的容器.其实ArrayList底层也是用数组进行实现的,今天我们就自己使用数组实现ArrayList的功能. 一.整体框架 废话不多说,我们以存放int类型元素为例,看一下ArrayList需要的成员变量和需要实现的方法. public class ArrayList private int size;//用来记录实际存储元素个数 private

  • JDK1.8中ArrayList是如何扩容的

    ArrayList简介: ArrayList实现了List接口它是一个可调整大小的数组可以用来存放各种形式的数据.并提供了包括CRUD在内的多种方法可以对数据进行操作但是它不是线程安全的,外ArrayList按照插入的顺序来存放数据. 在讲扩容机制之前,我们需要了解一下ArrayList中最主要的几个变量: private static final int DEFAULT_CAPACITY = 10;//数组默认初始容量 private static final Object[] EMPTY_E

  • Java中Arraylist动态扩容方法详解

    前言 本文主要给大家介绍了关于Java中Arraylist动态扩容的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. ArrayList 概述 ArrayList是基于数组实现的,是一个动态数组,其容量能自动增长.ArrayList不是线程安全的,只能用在单线程环境下.实现了Serializable接口,因此它支持序列化,能够通过序列化传输:实现了RandomAccess接口,支持快速随机访问,实际上就是通过下标序号进行快速访问:实现了Cloneable接口,能被克隆.

  • 分析Java中ArrayList与LinkedList列表结构的源码

    一.ArrayList源码分析(JDK7) ArrayList内部维护了一个动态的Object数组,ArrayList的动态增删就是对这个对组的动态的增加和删除. 1.ArrayList构造以及初始化 ArrayList实例变量 //ArrayList默认容量 private static final int DEFAULT_CAPACITY = 10; //默认空的Object数组, 用于定义空的ArrayList private static final Object[] EMPTY_ELE

  • Java中ArrayList和LinkedList区别

    目录 1 前言 2 数据结构的区别 2.1 ArrayList 2.2 LinkedList 2.3 使用场景 3 源码分析 3.1 ArrayList核心源码 3.2 LinkedList核心源码 4 码农来洞见 4.1为什么ArrayList比LinkedList要快 4.2 注意ArrayList不同JDK版本源码 4.3 高并发下如何保证集合数据的同步 4.4 为什么Java的Vector类被认为是过时的或者废弃的 1 前言 许多语言,例如 Perl ,Python 和 Ruby ,都有

  • Java中ArrayList类的使用方法

    Java中ArrayList类的用法 1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和IList接口 灵活的设置数组的大小 2.如何使用ArrayList 最简单的例子: ArrayList List = new ArrayList(); for( int i=0;i <10;i++ ) //给数组增加10个Int元素 List.Add(i); //..

  • java arrayList遍历的四种方法及Java中ArrayList类的用法

    java arrayList遍历的四种方法及Java中ArrayList类的用法 package com.test; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ArrayListDemo { public static void main(String args[]){ List<String> list = new ArrayList<String

随机推荐