Java进阶(3)——手动实现ArrayList 源码的初步理解分析 数组插入数据和删除数据的问题
目录
- 引出
- 手动实现ArrayList
- 定义接口MyList<T>
- 写ArrayList的实现类
- 增加元素
- 删除元素
- 写测试类进行测试
- 数组插入数据?
- 总结
引出
1.ArrayList的结构分析,可迭代接口,是List的实现;
2.数组增加元素和删除元素的分析,何时扩容,如何扩容;
3.插入数据的复杂度O(N);
4.数组特点:查找和修改容易O(1);增加和删除复杂O(N);
手动实现ArrayList

定义接口MyList<T>
package com.tianju.book.jpa.mlist;/*** 手工打造ArrayList*/
public interface MyList<T> {/*** 增加一个元素,涉及到容量的变化*/void add(T t);/*** 根据索引删除元素* @param index 要删除元素的索引,超过索引?索引不存在?*/void remove(int index);/*** 根据索引修改一个元素* @param index 要修改的索引* @param t 修改的值*/void set(int index,T t);/*** 根据索引获取元素* @param index 索引* @return 获取的元素*/T get(int index);int size();String toString();}
写ArrayList的实现类
增加元素
- 如果放不下怎么办?如何扩容?
- 扩容后如何操作?
扩容:每次为原来的1.5倍

如果放不下,就扩容;
扩容后把原来的数据一个一个再放回去;

删除元素
源码分析

- 删除头部,尾部,中间——最一般的就是中间元素被删除;
- 此时需要跳过被删除的元素,把没有被删除的放回去;

package com.tianju.book.jpa.mlist;public class MyArrayList<T> implements MyList<T> {private int size; // 不写初始值为0private Object[] elementData = new Object[5]; // 自己的ArrayList的默认大小是5@Overridepublic void add(T t) {// 如果放不下就要扩容if (size+1>=elementData.length){// >> 位运算,右移相当于除以2,所以新的长度是原来的1.5倍int newLen = elementData.length + (elementData.length>>1);// 这里相当于新建一个数组,把原来的一个一个放进去,然后把elementData指向新的数组
// elementData = Arrays.copyOf(elementData, newLen); // arrays工具类的实现Object[] newElementData = new Object[newLen];for(int i=0;i<elementData.length;i++){newElementData[i] = elementData[i];}elementData = newElementData;System.out.println("扩容后长度"+elementData.length);}elementData[size] = t;//把新的元素放过来size = size + 1; // 新的size比原来加1}@Overridepublic void remove(int index) {// 删除怎么搞?// 删除头部?尾部?中间?// 这里采用新建一个数组,跳过要删除的那个元素,一个一个再放回去Object[] newElementData = new Object[elementData.length]; // 和原来大小一样int j = 0; // 新的索引for (int i=0;i<size;i++){if (i==index){System.out.println(index+"跳过: "+elementData[i]);continue;}newElementData[j] = elementData[i];j++; // 跳过被删除的那个索引}elementData = newElementData; // 再指向新的数组size--; // 删除元素后size-1}@Overridepublic void set(int index, T t) {// 修改的复杂度为O(1)if (index>=size){throw new IndexOutOfBoundsException("索引越界");}elementData[index] = t;}@Overridepublic T get(int index) {// 根据索引获取元素的复杂度也为O(1)// 需要判断索引是不是超了if (index>=size){throw new IndexOutOfBoundsException("索引越界");}return (T) elementData[index];}@Overridepublic int size() {return this.size;}@Overridepublic String toString(){String str ="[";for (int i =0;i<size;i++){str += elementData[i] + ",";}str +="]";return str;}
}
写测试类进行测试
package com.tianju.book.jpa.mlist;import java.util.ArrayList;
import java.util.List;public class MyListTest {public static void main(String[] args) {MyList<String> myList = new MyArrayList<>();System.out.println(myList.size());myList.add("Peter001");myList.add("Peter002");myList.add("Peter003");myList.add("Peter004");System.out.println(myList.size());myList.add("Peter005");System.out.println("目前List中元素的数量"+myList.size());System.out.println(myList);System.out.println("*******删除一个元素*******");myList.remove(1);System.out.println(myList);System.out.println("删除元素后list长度:"+myList.size());myList.add("shirley");System.out.println("新增shirley元素后list:"+myList);System.out.println("长度:"+myList.size());System.out.println("*******修改一个元素*******");myList.set(0, "zgg");System.out.println(myList);System.out.println("*******查询一个元素*******");String s = myList.get(2);System.out.println("索引为2的元素为:"+s);System.out.println("索引越界的情况");System.out.println(myList.get(10));List<String> strings = new ArrayList<>();System.out.println(strings.size());}
}

数组插入数据?

插人和删除的花费却潜藏着昂贵的开销,这要看插入和删除发生在什么地方。最坏的情形下,在位置0的插入(即在表的前端插入)首先需要将整个数组后移一个位置以空出空间来,而删除第一个元素则需要将表中的所有元素前移一个位置,因此这两种操作的最坏情况为O(N)。
平均来看,这两种操作都需要移动表的一半的元素,因此仍然需要线性时间。另一方面,如果所有的操作都发生在表的高端,那就没有元素需要移动,而添加和删除则只花费O(1)时间。
存在许多情形,在这些情形下的表是通过在高端进行插入操作建成的,其后只发生对数组的访问(即只有findKth操作)。在这种情况下,数组是表的一种恰当的实现。然而,如果发生对表的一些插入和删除操作,特别是对表的前端进行,那么数组就不是一种好的选择。另一种数据结构:链表(linked list)。
总结
1.ArrayList的结构分析,可迭代接口,是List的实现;
2.数组增加元素和删除元素的分析,何时扩容,如何扩容;
3.插入数据的复杂度O(N);
4.数组特点:查找和修改容易O(1);增加和删除复杂O(N);
相关文章:
Java进阶(3)——手动实现ArrayList 源码的初步理解分析 数组插入数据和删除数据的问题
目录 引出手动实现ArrayList定义接口MyList<T>写ArrayList的实现类增加元素删除元素 写测试类进行测试数组插入数据? 总结 引出 1.ArrayList的结构分析,可迭代接口,是List的实现; 2.数组增加元素和删除元素的分析,何时扩容…...
若依前端npm run dev启动时报错
本文主要解决问题:若依前端npm run dev启动时报错,解决办法。 目录 1、第1种解决方案(亲测有效) 2、第2种解决方案(亲测有效) Error: error:0308010C:digital envelope routines::unsupportedat new Hash (node:internal/crypto/hash:67:19)at Object.createHash (node…...
实战项目:基于主从Reactor模型实现高并发服务器
项目完整代码仿mudou库one thread one loop式并发服务器实现: 仿muduo库One Thread One Loop式主从Reactor模型实现⾼并发服务器:通过模拟实现的⾼并发服务器组件,可以简洁快速的完成⼀个⾼性能的服务器搭建。并且,通过组件内提供的不同应⽤层…...
iTOP-RK3568开发板ubuntu环境下安装Eclipse
eclipse 是使用 Java 语言开发的,一个 Java 应用程序,这意味着 eclipse 只能运行在 Java虚拟机上。倘若没有安装 JDK(Java Development Kit),即使在 ubuntu 上安装了 eclipse,也不能运行,所以要…...
大气热力学
大气稳定度 大气稳定度又称为大气层结稳定度(贺德馨,2006)。大气层结指的是大气温度和湿度在垂直方向上的分布,对大气中污染物的扩散起着重要的作用。在静止大气中,假定气团受到垂直方向的扰动后,有一个向上的微小位移,如果大气层…...
【RabbitMQ】消息队列-RabbitMQ篇章
文章目录 1、RabbitMQ是什么2、Dokcer安装RabbitMQ2.1安装Dokcer2.2安装rabbitmq 3、RabbitMQ入门案例 - Simple 简单模式4、RabbitMQ的核心组成部分4.1 RabbitMQ整体架构4.2RabbitMQ的运行流程 5、RabbitMQ的模式5.1 发布订阅模式--fanout 1、RabbitMQ是什么 RabbitMQ是一个开…...
W5100S-EVB-PICO 做UDP Server进行数据回环测试(七)
前言 前面我们用W5100S-EVB-PICO 开发板在TCP Client和TCP Server模式下,分别进行数据回环测试,本章我们将用开发板在UDP Server模式下进行数据回环测试。 UDP是什么?什么是UDP Server?能干什么? UDP (User Dataqram …...
Redis如何处理内存溢出的情况?
当Redis的内存使用达到上限时,会出现内存溢出的情况。Redis提供了几种处理内存溢出的机制: 内存淘汰策略:Redis提供了多种内存淘汰策略,用于在内存不足时选择要移除的键。常见的淘汰策略包括: LRU(Least Re…...
高效数据传输:轻松上手将Kafka实时数据接入CnosDB
本篇我们将主要介绍如何在 Ubuntu 22.04.2 LTS 环境下,实现一个KafkaTelegrafCnosDB 同步实时获取流数据并存储的方案。在本次操作中,CnosDB 版本是2.3.0,Kafka 版本是2.5.1,Telegraf 版本是1.27.1 随着越来越多的应用程序架构转…...
【探索Linux】—— 强大的命令行工具 P.3(Linux开发工具 vim)
阅读导航 前言vim简介概念特点 vim的相关指令vim命令模式(Normal mode)相关指令插入模式(Insert mode)相关指令末行模式(last line mode)相关指令 简单vim配置(附配置链接)温馨提示 前言 前面我们讲了C语言的基础知识,也了解了一些数据结构&…...
AgentBench::AI智能体发展的潜在问题一
从历史上看,几乎每一种新技术的广泛应用都会在带来新机遇的同时引发很多新问题,AI智能体也不例外。从目前的发展看,AI智能体的发展可能带来的新问题可能包括如下方面: 第一是它可能带来涉及个人数据、隐私,以及知识产权的法律纠纷的大幅增长。要产生一个优秀的AI智能体,除…...
【2023年11月第四版教材】《第5章-信息系统工程之软件工程(第二部分)》
《第5章-信息系统工程之软件工程(第二部分)》 1.3 软件设计1.4 软件实现[补充第三版教材内容] 1.5 部署交付 1.3 软件设计 1、结构化设计SD是一种面向数据流的方法,它以SRS和SA阶段所产生的DFD和数据字 典等文档为基础…...
OpenCV(二)——图像基本处理(二)
目录 2.图像的几何变换 2.1 图像平移 2.2 图像缩放 2.3 图像旋转 2.4 仿射变换 2.5 透视变换...
Redis—缓存
目录标题 缓存雪崩发生场景解决方案针对Redis宕机的缓存雪崩解决方案 缓存击穿发生场景解决方案 缓存穿透发生场景解决方案布隆过滤器 数据库和缓存数据一致性 缓存雪崩 大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大…...
第三章 图论 No.10无向图的双连通分量
文章目录 定义Tarjan求e-DCCTarjan求v-DCC395. 冗余路径1183. 电力396. 矿场搭建 定义 无向图有两种双连通分量 边双连通分量,e-DCC点双连通分量,v-DCC 桥:删除这条无向边后,图变得不连通,这条边被称为桥 边双连通分…...
Java学习手册——第二篇面向对象程序设计
Java学习手册——第二篇面向对象 1. 结构化程序设计2. 面向对象 第一章我们已经介绍了Java语言的基础知识,也知道他能干什么了, 那我们就从他的设计思想开始入手吧。 接触一个语言之前首先要知道他的大方向,设计思想是什么样的, 这…...
Redis实战:Redis的安装及简单使用
本片将介绍 Redis 的安装及简单使用 文章目录 1、Redis安装1.1、Windows下Redis的安装1.2、Linux下Redis的安装1.3、Mac下Redis的安装(使用Homebrew) 2、Redis使用2.1、启动服务端客户端2.2、Redis简单命令 3、Redis命令大全 1、Redis安装 1.1、Windows…...
Linux学习之初识Linux
目录 一.Linux的发展历史及概念 1.什么是Linux UNIX发展的历史: Linux发展历史: 2. 开源 商业化发行版本 二. 如何搭建Linux环境 Linux 环境的搭建方式主要有三种: 1. 直接安装在物理机上 2. 使用虚拟机软件 3. 使用云服务器 三. …...
神经网络基础-神经网络补充概念-29-为什么使用深层表示
概念 深层表示(Deep Representation)是指在深度神经网络的多个隐藏层中逐层提取和学习数据的特征表示。 使用深层表示的原因 高维特征提取:深层神经网络可以从原始数据中自动学习高维抽象特征。每个隐藏层都对数据进行一些变换,…...
2023最新水果编曲软件FL Studio 21.1.0.3267音频工作站电脑参考配置单及系统配置要求
音乐在人们心中的地位日益增高,近几年音乐选秀的节目更是层出不穷,喜爱音乐,创作音乐的朋友们也是越来越多,音乐的类型有很多,好比古典,流行,摇滚等等。对新手友好程度基本上在首位,…...
2026 AI低代码实测:原理拆解+主流形态,避坑指南
2026年,AI低代码早已不是“概念炒作”,而是企业数字化转型的核心工具。Gartner预测,2026年全球70%以上新应用将采用低代码/无代码构建,较2023年45%的渗透率实现跨越式增长;IDC数据显示,同期全球AI低代码市场…...
The import xxx.xxx.xxx is never used
The import xxx.xxx.xxx is never used List is a raw type. References to generic type List<E> should be parameterized Dead code The value of the local variable d is not used代码洁癖啊,为啥这些这么多黄色警告都不处理呢。 没有用的代码࿰…...
从一次数据解析Bug说起:彻底搞懂QString的toLocal8Bit、toUtf8和toLatin1该用哪个
从一次数据解析Bug说起:彻底搞懂QString的编码转换选择 上周排查一个网络协议解析问题时,遇到一个典型的编码陷阱:服务端返回的GBK编码数据包,在Qt客户端用toUtf8()解析后出现乱码。这个看似简单的编码问题背后,隐藏着…...
仅限本周开放|Perplexity编程搜索高阶指令集(含12条未公开$context参数),错过再等半年!
更多请点击: https://codechina.net 第一章:Perplexity编程教程搜索概览 Perplexity 是一款以实时网络检索与推理能力见长的 AI 工具,其在编程学习场景中展现出独特优势——它不依赖静态知识库,而是动态调用最新技术文档、GitHub…...
Python(while循环)
目录 1.while 循环的基本概念 1.1 语法格式 1.2 最简单的示例 1.3 while 与 for 的对比 2. 代码执行顺序详解 3. 无限循环及其控制 3.1 无限循环的基本写法 3.2 避免无限循环的常见错误 4. break、continue 与 else 4.1 break:提前终止整个循环 4.2 cont…...
Java Stream流式编程实战
前言 在现代软件开发中,Java Stream流式编程实战是一个非常重要的技术点。本文将从原理到实践,带你深入理解这一技术,并通过完整的代码示例帮助你快速掌握核心知识点。 核心概念 基本原理 Java Stream流式编程实战的核心在于理解其底层机制。…...
万物智联城市:TurMass™ Mesh 打造稳定可靠的物联底座
随着数字中国建设深入推进,智慧城市已从概念落地为城市治理与民生服务的现实场景。从市政设施智能运维、公共安全全域感知,到环境监测精准布控、便民服务高效触达,城市运行的每一环都离不开稳定、高效、低成本的物联网连接支撑。然而…...
Hyper-V虚拟机文件迁移避坑指南:从C盘挪走Ubuntu,释放系统盘空间
Hyper-V虚拟机文件迁移实战:安全释放C盘空间的完整方案 当你在Windows系统上使用Hyper-V运行Ubuntu虚拟机时,是否注意到C盘空间正在被悄悄吞噬?许多技术爱好者初次接触Hyper-V时,往往直接采用默认设置,将所有虚拟机文件…...
TensorFlow GPU内存分配失败怎么办?教你一招避坑
💓 博客主页:瑕疵的CSDN主页 📝 Gitee主页:瑕疵的gitee主页 ⏩ 文章专栏:《热点资讯》 TensorFlow GPU内存分配失败的终极解决方案:一招避坑指南 目录 TensorFlow GPU内存分配失败的终极解决方案࿱…...
【懒人专用】Windows 端 Open Claw v 2.7.5 全自动部署图文教程
📌 前言 2026 年开源圈热门的「数字员工」OpenClaw(昵称小龙虾),GitHub 星标突破 28 万,凭借本地运行 零代码操作 自动干活的核心优势广受关注!很多人误以为它是普通聊天 AI,实则是能真正操控…...
