提高Java编程效率:ArrayList类的使用技巧

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前言

  在Java开发中,我们经常需要使用集合类来存储和操作数据。而ArrayList类是Java中最常用的集合类之一。本文将对ArrayList类进行详细讲解,帮助读者更好地了解并应用ArrayList类。

摘要

  本文将介绍Java中的ArrayList类,包括其基本概念、实现原理和应用场景,同时对ArrayList类的优缺点进行分析,最后提供ArrayList类的类代码方法介绍和测试用例,以及全文小结和总结。

ArrayList类

简介

  ArrayList是Java语言中的一个集合类,属于Java Collections Framework中的List接口的实现类。与数组相比,ArrayList类具有动态扩容、插入和删除元素方便等优点。ArrayList类底层是使用数组来实现的,因此其性能与数组相当。

源代码解析

  1. ArrayList类的定义
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {  
    //...
}

  从上面的代码可以看出,ArrayList类实现了List接口和RandomAccess接口,同时继承了AbstractList类,实现了Cloneable和Serializable接口。

  如下是部分源码截图:

在这里插入图片描述

  1. 动态扩容实现

  在ArrayList类中,需要使用数组来存储数据,但是数组创建时需要指定长度,因此无法支持动态扩容。为了解决这个问题,ArrayList类将数组的容量设置为默认值10。当数据存储空间不足时,ArrayList类会通过grow方法动态调整数组长度。

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);
}

  在上述代码中,grow方法会根据当前数组长度计算出新的数组长度,然后调用Arrays.copyOf方法将原数组中的元素复制到新数组中。需要注意的是,新数组长度不能超过MAX_ARRAY_SIZE,否则会抛出OutofMemoryError异常。
  如下是部分源码截图:

在这里插入图片描述

  1. 插入和删除元素实现

  对于插入和删除元素操作,ArrayList类提供了add和remove方法。

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // 是否需要扩容
    elementData[size++] = e;
    return true;
}

public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; //清空最后一个元素

    return oldValue;
}

  在上述代码中,add方法中的ensureCapacityInternal方法判断当前数组长度是否满足需求,如果数组空间不足,则会调用grow方法对数组进行扩容。然后将新元素添加到数组末尾。remove方法中会先检查下标是否合法,然后将待删除元素后面的元素依次向前移动一位,然后将最后一个元素位置清空。

应用场景案例

  ArrayList类适用于存储数量不确定的数据,并且需要随时对数据进行插入和删除操作的场景。例如,需要存储动态数据集合或读取数据文件时,ArrayList都是很好的选择。

优缺点分析

优点

  1. 支持动态扩容,可以动态增加存储空间。
  2. 插入和删除元素方便,不需要自行维护数组下标。
  3. 可以存储任意类型的数据,具有泛型特性。
  4. 支持快速随机访问元素。

缺点

  1. 数组默认长度为10,如果预估数量过多,需要手动调用ensureCapacity方法进行扩容,否则可能会发生内存溢出。
  2. 插入和删除元素时,需要将元素后面的元素全部向前或向后移动,性能会受到影响。

类代码方法介绍

构造方法

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

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);
    }
}

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

增加元素方法

public boolean add(E e) {
    ensureCapacityInternal(size + 1);
    elementData[size++] = e;
    return true;
}
public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // 是否需要扩容
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

拓展:

  如上是 Java 中 ArrayList 类的 add 方法的两个重载版本。

  第一个方法 add(E e) 是在列表末尾添加元素,它首先会调用 ensureCapacityInternal 方法来确保内部数组 elementData 的容量足够存放新的元素。如果容量不够,则进行扩容操作。然后将元素添加到数组的末尾,最后返回 true

  第二个方法 add(int index, E element) 是在指定位置添加元素,它首先会调用 rangeCheckForAdd 方法来检查指定的位置是否越界。然后调用 ensureCapacityInternal 方法确保数组容量足够,接着使用 System.arraycopy 方法将指定位置及其后面的元素向后移动一个位置。最后在指定位置插入新元素,更新列表的大小。

删除元素方法

public boolean remove(Object o) {
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

拓展:

  这段代码是ArrayList类中的remove方法,可以用来从列表中删除指定对象或指定索引位置的元素。下面对代码进行分析:

  1. remove(Object o)方法:
  • 如果要删除的对象o为null,则使用for循环遍历整个列表,如果找到了值为null的元素,则调用fastRemove方法快速删除该元素,并返回true;否则返回false。
  • 如果要删除的对象o不为null,则使用for循环遍历整个列表,如果找到了与o相等的元素,则调用fastRemove方法快速删除该元素,并返回true;否则返回false。
  1. remove(int index)方法:
  • 首先使用rangeCheck方法检查索引index是否有效,如果无效则抛出IndexOutOfBoundsException异常。
  • 然后对modCount进行自增操作,表示列表结构已经发生了变化。
  • 接着获取索引位置为index的元素的值oldValue。
  • 如果要删除的元素不在列表末尾,则使用System.arraycopy方法将该元素后面的所有元素向前移动一位,从而删除该元素。
  • 最后将列表的长度减1,并将最后一个元素设为null,以便让垃圾回收机制处理该元素。

  总体来说,这段代码的实现比较简单,其中重点在于快速删除元素的实现,即fastRemove方法。

元素查找方法

public int indexOf(Object o) {
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

拓展:

  上述代码中,定义了一个名为indexOf的方法,该方法返回对象o在数组elementData中第一次出现的索引位置,如果数组中不包含该对象,则返回-1。如果o为null,则遍历数组并查找为空的元素,若找到,则返回其索引位置。如果o不为null,则遍历数组并使用equals方法比较元素,若找到相等的元素,则返回其索引位置。

  同时,该代码还定义了一个名为contains的方法,该方法调用indexOf方法来判断数组中是否包含对象o,并返回一个布尔值。如果返回值大于等于0,则表示数组中包含该对象,返回true;否则,返回false。

测试用例

测试代码演示

package com.example.javase.se.classes;

import java.util.ArrayList;

/**
 * @Author ms
 * @Date 2023-11-02 19:13
 */
public class ArrayListTest {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        // Test add
        list.add("Hello");
        list.add("World");
        list.add("Java");
        System.out.println(list.get(0)); // Output: Hello
        System.out.println(list.get(1)); // Output: World
        System.out.println(list.get(2)); // Output: Java

        // Test remove
        list.remove(2);
        System.out.println(list.contains("Java")); // Output: false

        // Test indexOf
        System.out.println(list.indexOf("World")); // Output: 1
    }
}

测试结果

  根据如上测试用例,本地测试结果如下,仅供参考,你们也可以自行修改测试用例或者添加更多的测试数据或测试方法,进行熟练学习以此加深理解。

在这里插入图片描述

测试代码分析

  根据如上测试用例,在此我给大家进行深入详细的解读一下测试代码,以便于更多的同学能够理解并加深印象。

  该代码定义了一个名为ArrayListTest的类,用于测试ArrayList的基本操作。在主方法中,首先创建了一个ArrayList<String>对象,并用add()方法添加了三个字符串元素:“Hello”、“World"和"Java”。

  然后又测试了remove()方法,将索引为2的元素(即"Java")从集合中移除,并使用contains()方法验证该元素是否存在,输出结果为false。

  最后,测试了indexOf()方法,查找"World"在集合中的索引位置,输出结果为1。

小结

  • ArrayList是Java中最常用的集合类之一,底层是由数组实现的。
  • ArrayList支持动态扩容,插入和删除元素方便,可以存储任何类型的数据。
  • ArrayList的优点是支持动态扩容,插入和删除元素方便,可以存储任何类型的数据,同时支持快速访问元素。
  • ArrayList的缺点是默认长度为10,如果预估数量过多,需要手动扩容,扩容时需要移动数据,性能受到影响。

总结

  本文对Java中的ArrayList类进行了详细介绍,包括其定义、实现原理、应用场景、优缺点分析、常用方法等。ArrayList类是Java中最常用的集合类之一,它具有动态扩容功能和插入、删除元素方便等优点,适用于存储数量不确定的数据,并需要随时对数据进行插入和删除操作的场景。需要注意的是,在使用ArrayList类时需要注意预估存储数据的数量,并在必要时手动调用ensureCapacity方法进行扩容,否则可能会发生内存溢出。

  本文还提供了ArrayList类的构造方法、增加元素方法、删除元素方法和元素查找方法等代码实现,并提供了测试用例帮助读者更好地了解和应用ArrayList类。

  最后,希望通过本文的介绍,读者对ArrayList类有更深入的了解,并能在实际开发中充分利用其优点,避免其缺点,提高程序的性能和效率。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。

⭐️若有疑问,就请评论留言告诉我叭。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/647390.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

虹科Pico汽车示波器 | 免拆诊断案例 | 2012 款雪佛兰科鲁兹车偶尔多个故障灯异常点亮

故障现象 一辆2012款雪佛兰科鲁兹车&#xff0c;搭载1.8 L 发动机&#xff0c;累计行驶里程约为9.6万km。该车组合仪表上的发动机故障灯、ABS故障灯及动力转向故障灯偶尔异常点亮&#xff0c;同时发动机转速表和发动机冷却液温度表的指针会突然归零&#xff0c;严重时发动机无…

【Linux 网络】网络基础(三)(网络层协议:IP 协议)

在复杂的网络环境中确定一个合适的路径。 一、TCP 与 IP 的关系 IP 层的核心作用是定位主机&#xff0c;具有将数据从主机 A 发送到主机 B 的能力&#xff0c;但是能力并不能保证一定能够做到&#xff0c;所以这时就需要 TCP 起作用了&#xff0c;TCP 可以通过超时重传、拥塞控…

[Vulnhub]Vulnix 通过NFS挂载+SSH公钥免密登录权限提升

端口扫描 Server IP AddressPorts Open192.168.8.103TCP:22/tcp, 25/tcp, 79/tcp, 110/tcp, 111/tcp, 143/tcp, 512/tcp, 513/tcp, 514/tcp, 993/tcp, 995/tcp, 2049/tcp, 37522/tcp, 42172/tcp, 43219/tcp, 47279/tcp, 54227/tcp $ nmap -p- 192.168.8.103 -sV -sC --min-ra…

Nginx实战(安装部署、常用命令、反向代理、负载均衡、动静分离)

文章目录 1. nginx安装部署1.1 windows安装包1.2 linux-源码编译1.3 linux-docker安装 2. nginx介绍2.1 简介2.2 常用命令2.3 nginx运行原理2.3.1 mater和worker2.3.3 Nginx 的工作原理 2.4 nginx的基本配置文件2.4.1 location指令说明 3. nginx案例3.1 nginx-反向代理案例013.…

python基于深度学习的聊天机器人设计

python基于深度学习的聊天机器人设计 开发语言:Python 数据库&#xff1a;MySQL所用到的知识&#xff1a;Django框架工具&#xff1a;pycharm、Navicat、Maven 系统功能实现 登录注册功能 用户在没有登录自己的用户名之前只能浏览本网站的首页&#xff0c;想要使用其他功能都…

ROCm上来自Transformers的双向编码器表示(BERT)

14.8. 来自Transformers的双向编码器表示&#xff08;BERT&#xff09; — 动手学深度学习 2.0.0 documentation (d2l.ai) 代码 import torch from torch import nn from d2l import torch as d2l#save def get_tokens_and_segments(tokens_a, tokens_bNone):""&qu…

html中被忽略的简单标签

1&#xff1a; alt的作用是在图片不能显示时的提示信息 <img src"https://img.xunfei.cn/mall/dev/ifly-mall-vip- service/business/vip/common/202404071019208761.jp" alt"提示信息" width"100px" height"100px" /> 2&#…

CTF之Web_python_block_chain

这种题对于我来说只能看大佬的wp&#xff08;但是这一题是wp都看不懂&#xff0c;只能表达一下我的理解了&#xff09; &#xff08;最后有简单方法&#xff0c;前面一种没看懂没关系&#xff09; 下面这一部分是首页的有用部分 访问/source_code,得到源码&#xff1a; # -*-…

mysql之递归sql

mysql之递归sql 递归sql在一些公司是不允许使用的&#xff0c;会涉及数据库压力&#xff0c;所以会在代码里递归查询&#xff0c;但有些公司开发流程没有规定&#xff0c;且数据库数据量不大&#xff0c;之前写过好几遍了&#xff0c;老是记不住&#xff0c;记录一下 通过父级…

LiveGBS流媒体平台GB/T28181用户手册-版本信息:查看机器码、切换查看流媒体服务

LiveGBS流媒体平台GB/T28181用户手册--版本信息:查看机器码、切换查看流媒体服务 1、版本信息1.1、查看机器码1.2、多个流媒体服务1.3、提交激活 2、搭建GB28181视频直播平台 1、版本信息 版本信息页面&#xff0c;可以查看到信令服务 流媒体服务相关信息&#xff0c;包含硬件…

MySQL--存储引擎

一、存储引擎介绍 1.介绍 存储引擎相当于Linux的文件系统&#xff0c;以插件的模式存在&#xff0c;是作用在表的一种属性 2.MySQL中的存储引擎类型 InnoDB、MyISAM、CSV、Memory 3.InnoDB核心特性的介绍 聚簇索引、事务、MVCC多版本并发控制、行级锁、外键、AHI、主从复制特…

网络安全等级保护:正确配置 Linux

正确配置 Linux 对Linux安全性的深入审查确实是一项漫长的任务。原因之一是Linux设置的多样性。用户可以使用Debian、Red Hat、Ubuntu或其他Linux发行版。有些可能通过shell工作&#xff0c;而另一些则通过某些图形用户界面&#xff08;例如 KDE 或 GNOME&#xff09;工作&…

零基础学Java第二十三天之网络编程Ⅱ

1. InetAddress类 用来表示主机的信息 练习&#xff1a; C:\Windows\system32\drivers\etc\ hosts 一个主机可以放多个个人网站 www.baidu.com/14.215.177.37 www.baidu.com/14.215.177.38 www.taobao.com/183.61.241.252 www.taobao.com/121.14.89.253 2. Socket 3.…

细粒度图像分类论文(AAM模型方法)阅读笔记

细粒度图像分类论文阅读笔记 摘要Abstract1. 用于细粒度图像分类的聚合注意力模块1.1 文献摘要1.2 研究背景1.3 本文创新点1.4 计算机视觉中的注意力机制1.5 模型方法1.5.1 聚合注意力模块1.5.2 通道注意力模块通道注意力代码实现 1.5.3 空间注意力模块空间注意力代码实现 1.5.…

Superset,基于浏览器的开源BI工具

BI工具是数据分析的得力武器&#xff0c;目前市场上有很多BI软件&#xff0c;众所周知的有Tableau、PowerBI、Qlikview、帆软等&#xff0c;其中大部分是收费软件或者部分功能收费。这些工具一通百通&#xff0c;用好一个就够了&#xff0c;重要的是分析思维。 我一直用的Tabl…

【数据结构/C语言】深入理解 双向链表

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;数据结构与算法 在阅读本篇文章之前&#xff0c;您可能需要用到这篇关于单链表详细介绍的文章 【数据结构/C语言】深入理解 单链表…

python内置函数map/filter/reduce详解

在Python中&#xff0c;map(), filter(), 和 reduce() 是内置的高级函数(实际是class)&#xff0c;用于处理可迭代对象&#xff08;如列表、元组等&#xff09;的元素。这些函数通常与lambda函数一起使用&#xff0c;以简洁地表达常见的操作。下面我将分别解释这三个函数。 1. …

echarts-地图

使用地图的三种的方式&#xff1a; 注册地图(用json或svg,注册为地图)&#xff0c;然后使用map地图使用geo坐标系&#xff0c;地图注册后不是直接使用&#xff0c;而是注册为坐标系。直接使用百度地图、高德地图&#xff0c;使用百度地图或高德地图作为坐标系。 用json或svg注…

Selenium 高频面试题及答案

1、什么是 Selenium&#xff1f;它用于做什么&#xff1f; Selenium 是一个用于自动化测试的开源框架。它提供了多种工具和库&#xff0c;用于模拟用户在不同浏览器和操作系统上的行为&#xff0c;并且可用于测试网页应用程序。 2、Selenium WebDriver 和 Selenium IDE 有何区…

【机器学习300问】100、怎么理解卷积神经网络CNN中的池化操作?

一、什么是池化&#xff1f; 卷积神经网络&#xff08;CNN&#xff09;中的池化&#xff08;Pooling&#xff09;操作是一种下采样技术&#xff0c;其目的是减少数据的空间维度&#xff08;宽度和高度&#xff09;&#xff0c;同时保持最重要的特征并降低计算复杂度。池化操作不…