首页 > 编程语言 >深入理解 Java 中 ArrayList 的底层原理

深入理解 Java 中 ArrayList 的底层原理

时间:2024-08-22 21:04:14浏览次数:6  
标签:扩容 Java ArrayList elementData minCapacity DEFAULTCAPACITY 数组 底层

在这篇博客中,我们将深入探讨ArrayList的底层实现原理,并通过逐步剖析ArrayList的源码来理解其内部工作机制。我们将重点关注ArrayList的创建、元素添加、扩容机制等关键点。

创建ArrayList集合对象

ArrayList<String> list = new ArrayList<>();

使用空参构造器创建ArrayList集合对象时,会调用其内部的默认构造方法:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

深入解析

  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA: 这是一个final修饰的静态常量,是一个空的Object数组:

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
  • elementData: ArrayList内部用于存储数据的数组。初始时,它指向一个空的Object数组。

    transient Object[] elementData;
    

关键点总结

  1. 利用空参构造器创建ArrayList集合对象时,底层会创建一个长度为0的数组elementData
  2. DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空数组,用于标记集合在添加第一个元素之前的状态。

向集合中添加元素

list.add("Hello World");

添加元素时,ArrayList内部会调用add方法:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}

深入解析

  • size: 表示ArrayList中当前元素的数量,初始值为0。

  • ensureCapacityInternal(size + 1): 确保ArrayList内部数组有足够的空间来存储新元素。如果没有足够空间,会触发扩容。

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    
  • calculateCapacity: 计算新的容量,如果当前elementData指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则返回默认初始容量10

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
    

关键点总结

  1. 第一次添加元素时,ArrayList内部会创建一个默认长度为10的数组来存储数据。
  2. size表示当前ArrayList中的元素数量,每次添加元素后都会增加。

扩容机制

ArrayList内部数组的容量不足以容纳新元素时,会触发扩容机制:

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    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倍(即oldCapacity + (oldCapacity >> 1))。

  • Arrays.copyOf: 创建一个新数组,将原数组中的数据复制到新数组中。

关键点总结

  1. ArrayList每次扩容时,容量增加至原来的1.5倍。
  2. 扩容后的新数组会替换旧数组,继续存储新元素。

潜在优化与最佳实践

  • 初始容量设置: 如果事先知道需要存储大量数据,可以通过指定初始容量来避免频繁扩容。例如:

    ArrayList<String> list = new ArrayList<>(100);
    
  • 扩容代价: 每次扩容都会进行数组复制,代价较高。在需要处理大量数据的场景中,建议提前设定合适的初始容量。


通过本文的解析,你应该对ArrayList的底层实现原理有了更加深入的理解。从空参构造到添加元素,再到扩容机制,ArrayList的每一步操作背后都隐藏着精妙的设计和实现逻辑。希望这篇博客能帮助你更好地掌握ArrayList的工作原理,写出更高效的代码。

标签:扩容,Java,ArrayList,elementData,minCapacity,DEFAULTCAPACITY,数组,底层
From: https://www.cnblogs.com/itcq1024/p/18374761

相关文章

  • [Java手撕]线程安全的转账
    首先来看线程不安全的转账publicclassBank{privateint[]accounts;publicBank(){this.accounts=newint[10];for(inti=0;i<10;i++){accounts[i]=1000;}}publicvoidtransfer(intfrom,int......
  • 一起学Java(3)-Java项目构建工具Gradle和Maven场景定位和优缺点对比
    在第一步创建的项目(java-all-in-one)项目里,我们提到了使用Gradle作为项目构建工具。看到这里,不知道你是否有疑惑,什么是项目构建工具。Java项目常用构建工具有哪些?都有什么特点?带着疑惑,本文对Java的构建工具进行一些梳理,以同步理解。从而使大家对我们项目中使用到的技术栈和技术......
  • Java多态
    1.多态1.1多态的概述(记忆)什么是多态不同类的对象在调用同一个方法时表现出来的多种不同行为多态的前提要有继承或实现关系要有方法的重写要有父类引用指向子类对象代码演示classAnimal{  publicvoideat(){    System.out.println("动物吃肉")......
  • Java设计模式之代理模式:静态代理VS动态代理,与其他模式的对比分析和案例解析
    一、代理模式简介代理模式(ProxyPattern)是一种结构型设计模式,它提供了一个代理对象,用来控制对另一个对象的访问。这种模式通常用于在访问对象时引入额外的功能,而不改变对象的接口。代理模式的核心思想是为其他对象提供一种代理,以控制对这个对象的访问。在现实生活中,代理模......
  • java 面向对象4
    1.java存在抽象类,不写函数的具体实现,需要再函数前边加上abstract修饰.这个和c++语法存在差别,但是同样抽象类不可以创建对象,可以用抽象类的引用指向子类创建的对象,这个用法在一定程度上使得接口一致.利于在开发中保持接口一致,避免接口混乱的问题.同时利用抽象类可以使得一些......
  • JavaSE基础知识分享(十三)
    写在前面今天继续讲Java中的网络编程的知识!网络编程概述计算机网络计算机网络是将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。例如:极域。网络......
  • Volatile的底层原理
    Volatile的底层原理volatile的特点被volatile修饰的变量具有如下特点:1.保证此变量对所有的线程的可见性,不能保证它具有原子性(可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的)2.禁止指令重排序优化3.volatile的读性能消耗与普通变量几乎相同,但是写......
  • Java中的static关键字
    static可以用来修饰成员变量,也能修饰成员方法。1.1static修饰成员变量Java中的成员变量按照有无static修饰分为两种:类变量、实例变量。它们的区别如下图所示: 由于静态变量是属于类的,只需要通过类名就可以调用:类名.静态变量实例变量是属于对象的,需要通过对象才能调用:对......
  • Java基础——自学习使用(static关键字)
    一、static关键字是什么?static修饰的代码属于类,定义的变量存储在方法区的静态常量池当中二、static可以修饰什么1.static修饰变量static修饰的变量叫做类变量,被所有该类产生的对象所共享,存储在方法区的静态常量池中2.static修饰方法static修饰是的方法属于静态方法,stat......
  • Java中对继承的学习
    继承目录继承继承的概念为什么需要继承继承的特性继承的优点和缺点继承的概念继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为......