Java ArrayList扩容机制原理深入分析

Java ArrayList扩容机制原理深入分析

在 Java 中,ArrayList 是一种动态数组,它可以自动扩容以适应数据的增长。了解 ArrayList 扩容机制的原理,有助于我们更好地理解和使用 ArrayList,提高代码效率。

ArrayList 扩容机制

ArrayList 内部使用数组来存储元素,当向 ArrayList 中添加元素时,如果当前数组已满,就需要扩容。下面是 ArrayList 扩容的基本流程:

  1. 获取当前 ArrayList 的容量 capacity 和当前 ArrayList 已存储的元素个数 size;
  2. 判断当前数组是否已满,即 size == capacity
  3. 如果数组已满,创建一个新的容量是原来容量 1.5 倍的数组,并将原数组中的元素复制到新数组中;
  4. 新数组成为 ArrayList 的内部数组。

下面是一个简单的示例:

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>(3);
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
    }
}

在上面的例子中,我们创建了一个容量为 3 的 ArrayList,并往里面添加了 6 个元素。在添加第 4 个元素时,由于数组已满,系统调用了 grow() 方法进行扩容。下面是 grow() 方法的源码:

private void grow(int minCapacity) {
    // 获取当前 ArrayList 容量
    int oldCapacity = elementData.length;
    // 计算新容量大小
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 如果新容量不足以满足最小容量需求,就使用最小容量作为新容量
    if (newCapacity < minCapacity)
        newCapacity = minCapacity;
    // 创建新的数组,并将原数组的元素复制到新数组中
    elementData = Arrays.copyOf(elementData, newCapacity);
}

可以看到,在扩容时,系统会计算出新的容量大小,并将原数组的元素复制到新数组中,从而保证数据的顺序不变。需要注意的是,在计算新容量大小时,采用了位运算 >> 来代替除法,以提高代码效率。

另外,在调用 grow() 方法扩容时,如果我们向 ArrayList 中添加大量元素,扩容的次数可能很多,从而导致效率降低。因此,我们在使用 ArrayList 时,尽量预留一定的容量,避免频繁扩容。

下面是一个添加 100 000 个元素的例子,可以看到,在初始容量为 100 000 的情况下,并不会出现扩容的情况:

import java.util.ArrayList;

public class Demo {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>(100000);
        for (int i = 0; i < 100000; i++) {
            list.add(i);
        }
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java ArrayList扩容机制原理深入分析 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • 关于springboot 配置date字段返回时间戳的问题

    那么首先需要说明一下什么是Spring Boot以及什么是时间戳。 Spring Boot是一个快速开发框架,可以帮助我们快速搭建起一个运作稳定、易于开发的Web应用程序。而时间戳则是指从某个固定时间点开始的总秒数,通常用于记录和计算时间。 在Spring Boot中,我们可以通过以下方式配置Date字段返回时间戳: 使用注解配置 我们可以在Date类型的字…

    Java 2023年5月20日
    00
  • 基于JDK8总结java中的interrupt

    基于JDK8总结java中的interrupt interrupt是Java中多线程编程中用来中断线程的机制,通过interrupt方法,可以将线程置于一个中断的状态中,线程可以根据自己的业务逻辑来决定如何响应这个中断。 interrupt的实现机制 在Java中,interrupt机制的实现是基于一个boolean类型的标记,这个标记被称作中断状态标记(I…

    Java 2023年5月26日
    00
  • SpringBoot整合SQLite数据库全过程

    下面我将为您详细讲解SpringBoot整合SQLite数据库的全过程,包括以下几个步骤: 导入SQLite依赖 配置SQLite数据源 创建实体类 创建DAO接口 创建Service层 创建Controller层 示例演示 1.导入SQLite依赖 在pom.xml文件中添加以下依赖: <dependency> <groupId>o…

    Java 2023年5月20日
    00
  • mybatis查询语句揭秘之参数解析

    下面是关于”mybatis查询语句揭秘之参数解析”的完整攻略。 什么是参数解析? 在Mybatis框架中,#{}和${}是两种常用的参数占位表达式。它们在执行sql语句时,代表不同的参数解析方式。 #{}表示的是预编译的SQL语句参数占位符,会将传入的参数使用JDBC的预编译功能进行替换,可以有效地防止SQL注入攻击。 ${}表示的是占位符,会将参数直接拼接…

    Java 2023年5月20日
    00
  • Java基数排序radix sort原理及用法解析

    Java基数排序(radix sort)原理及用法解析 简介 基数排序(radix sort)是一种线性时间非比较排序算法。该算法按照元素的每个位数进行排序。 对于待排序的整数集合,基数排序将集合中的元素按照它们的个位、十位、百位……的大小排序(可以理解为在固定位数的情况下逐个进行桶排序)。 基数排序的时间复杂度为 $O(d \cdot (n+k))$,其中…

    Java 2023年5月26日
    00
  • Java数组扩容实现方法解析

    Java 数组扩容实现方法解析 本文将详细介绍 Java 数组扩容的实现方法。数组是 Java 语言中最基本的数据结构之一,而数组的长度在初始化的时候就已经固定,不能动态调整。因此,为了能够动态地向数组中添加元素,我们需要用到数组扩容这一功能。 为什么要扩容 在实际开发中,经常会出现需要动态向数组中添加元素的情况。例如,我们需要一个可以动态增长的数组来保存用…

    Java 2023年5月27日
    00
  • Spring Boot 简介(入门篇)

    SpringBoot简介(入门篇) 什么是SpringBoot Spring Boot 是一个用于快速创建 Spring 应用程序的框架。它基于 Spring 框架,遵循“约定优于配置”的原则,提供了很多默认配置,简化了 Spring 应用程序的开发过程。 SpringBoot的优点 快速开发: Spring Boot 可以快速创建独立运行的 Spring …

    Java 2023年5月15日
    00
  • 基于Spring Security前后端分离的权限控制系统问题

    基于Spring Security前后端分离的权限控制系统是一个非常常见的开发需求。下面将提供完整攻略,从搭建环境、配置安全策略、实现权限控制等方面讲解该系统的具体实现。其中示例将分别展示两种不同的权限控制方式。 1. 搭建环境 首先,需要搭建一个Spring Boot项目,并且集成Spring Security。需要在项目中引入以下依赖: <depe…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部