Java ArrayList 详解:从动态数组到扩容机制与常见陷阱
Java ArrayList 详解:从动态数组到扩容机制与常见陷阱前言在 Java 开发中,ArrayList 是最常用的集合类之一。查询结果、商品列表、评论列表、菜单选项等业务数据,经常都会使用它来保存。
普通数组就像一排固定数量的座位:创建时有多少位置,后续就只能使用多少位置。ArrayList 则像一节可以不断扩建的车厢:底层仍然使用数组,但空间不足时,会自动创建更大的数组,并把原有元素搬过去。
本文从基础使用开始,逐步讲解 ArrayList 的底层结构、扩容机制、增删改查原理、遍历删除陷阱、线程安全问题以及常见使用误区。
本文源码分析主要以 JDK 8 为基础。较新的 JDK 对部分内部方法进行了重构,但 ArrayList 的核心思想并没有改变:
1234底层是数组容量不足时需要扩容根据下标访问速度快中间插入和删除需要移动元素
一、认识 ArrayList1.1 ArrayList 是什么ArrayList<E> 是 List<E> 接口的一个实现类,底层通过数组保存元素。
1List<String> names = new Arra ...
Java 集合框架入门:List、Set、Queue 与 Map
Java 集合框架入门:List、Set、Queue 与 Map前言在程序开发中,我们经常需要保存和处理一组数据,例如购物车中的商品、文章标签、排队等待执行的任务、学生姓名与成绩的对应关系。
数组虽然也能保存多个元素,但它的长度固定,增删元素不够灵活。Java 集合框架就像一套准备好的“数据收纳工具箱”:不同的容器有不同的摆放规则,也适用于不同的业务场景。
Java 集合框架主要分为两条路线:
Collection:保存一个个独立元素,下面包括 List、Set、Queue。
Map:保存键值对,例如“用户名 → 用户信息”。
需要特别注意:Map 属于集合框架的一部分,但它不是 Collection 的子接口。
一、为什么需要集合框架1.1 数组的局限数组适合保存数量比较固定的数据:
1234String[] names = new String[3];names[0] = "张三";names[1] = "李四";names[2] = "王五";
但是,当数据数量不断变化时,数组会显得不够灵活:
数组长度创建后不 ...
IDEA+exe4j+InnoSetup打包java项目为exe可执行文件
IDEA+exe4j+InnoSetup打包java项目为exe可执行文件[TOC]
一、前言将自己的java项目打包导出为windows桌面程序(exe)比较麻烦,我们希望达到的效果是导出的exe文件可以再其他没有java环境的电脑运行。
简单描述打包过程如下:
IDEA导出项目的jar包;
exe4j软件( exe4j下载链接 )第一次打包生成依赖java环境的exe可执行文件;
Inno Setup软件( Inno Setup Downloads )第二次打包生成不依赖环境的安装包。
具体操作步骤见下文。
二、什么是jar包在Java开发中,JAR(Java ARchive)包是一种将多个Java类文件及相关资源文件(如图像、配置文件等)打包成一个文件的格式。JAR包的扩展名为.jar,它是一个压缩文件,类似于ZIP文件,但用于Java程序的分发和执行。
打包成JAR包的过程通常是指将编写好的Java程序(包括源代码文件和其他资源文件)经过编译后,所有的.class文件和资源文件(如图片、配置文件等)一起打包成一个JAR文件。这种打包方式可以方便地部署、传输和执行Java应用 ...
设计模式 · 责任链模式(Chain of Responsibility Pattern)
设计模式 · 责任链模式(Chain of Responsibility Pattern)前言在业务系统中,经常会遇到“多级审批”“多层校验”“多步骤过滤”这类流程。
比如项目上线审批:
平时只需要三级负责人审批;
618 大促期间,需要额外经过二级负责人审批;
618 核心时间段,还需要一级负责人审批;
每一级审批通过后,才可以继续向下流转。
如果直接用 if-else 写,代码很快就会变成一大坨判断逻辑。新增审批级别、调整审批顺序、修改审批规则,都需要改原来的核心方法。
责任链模式的作用,就是把这些审批环节拆成一个个独立节点,再用 next 把它们串成一条链。
本文代码链接:https://github.com/likerhood/CodeDesignWork/tree/main/codedesign12.0-0
一、核心定义责任链模式(Chain of Responsibility Pattern) 是一种行为型设计模式,将请求的发送者和接收者解耦,让多个对象都有机会处理请求,将这些对象串成一条链,请求沿链传递,直到有对象处理它为止。
它的核心思想是:
将多个处理对象 ...
Java 动态代理详解:从 InvocationHandler 到 Mapper 接口代理
Java 动态代理详解:从 InvocationHandler 到 Mapper 接口代理前言在学习 Java 动态代理时,最容易产生疑问的代码通常是下面这一段:
12345678910111213InvocationHandler handler = (proxy, method, args) -> { Select select = method.getAnnotation(Select.class); System.out.println( select.value().replace("#{uId}", args[0].toString()) ); return args[0] + ",查询成功";};return (T) Proxy.newProxyInstance( mapperInterface.getClassLoader(), new Class<?>[]{mapperInterface& ...
设计模式 · 代理模式(Proxy Pattern)java
设计模式 · 代理模式(Proxy Pattern)前言在技术成长的路上,业务开发中的 CRUD 虽然熟悉,但框架和中间件背后的机制却常常被忽视。
你有没有想过:MyBatis 的 Mapper 接口只有接口定义,没有实现类,调用时却能执行 SQL 并返回数据——这是怎么做到的?
答案就是代理模式(Proxy Pattern)。MyBatis-Spring 在启动时扫描 DAO 接口,为每一个接口动态生成一个代理类,将该代理类注册到 Spring 容器中。调用接口方法时,实际上是代理类拦截了调用,从方法上的 @Select 等注解中读取 SQL,交给 SqlSession 执行,再将结果返回。
本章通过手写一个迷你版 MyBatis-Spring 代理注册流程,来深入理解代理模式的核心思想。
一、核心定义代理模式(Proxy Pattern) 是一种结构型设计模式,为另一个对象提供一个代理(替身或占位符),以控制对原对象的访问。
核心思想:在客户端与真实服务对象之间插入一个代理层,由代理负责访问控制、日志、缓存、懒加载等附加功能,而不改变真实对象
解决问题:直接访问真实对象有困难( ...
Java 异常处理:从 try-catch-finally 到项目最佳实践
Java 异常处理:从 try-catch-finally 到项目最佳实践前言程序运行时并不总是一帆风顺。文件可能不存在,网络可能超时,用户可能输入非法数据,对象可能是 null。这些“计划之外的情况”,就是异常处理要面对的问题。
异常就像程序道路上的警示牌:它告诉我们“这里出问题了”,同时也给我们一个机会,决定是修复、提示、重试、回滚,还是把问题继续向上抛。
Java 的异常机制,就像给程序建立了一套“故障处理通道”:正常情况下,代码沿着主流程向前执行;一旦出现异常,就可以通过 throw 发出问题,通过 catch 接住并处理,通过 throws 声明风险,还可以利用异常链保留最初的故障原因。
本文将从异常的基本概念开始,逐步讲解 Java 异常体系、try-catch-finally、throw 与 throws、自定义异常、异常链以及 try-with-resources。
一、异常是什么1.1 异常的核心定义异常是程序执行过程中出现的非正常情况。它会打断当前正常流程,把问题交给异常处理机制。
比如:
1int result = 10 / 0;
这行代码会抛出:
1java ...
Java static 关键字从浅入深
Java static 关键字从浅入深前言static 是 Java 里非常常见的关键字。它的核心意思是:这个成员属于类,而不是属于某一个对象。
如果把类比作一张“设计图”,对象就是按设计图造出来的一台台机器。普通字段是每台机器自己的零件,static 字段则像挂在工厂墙上的公共看板,所有机器看到的是同一份。
一、static 的基本概念1.1 static 修饰什么static 可以修饰变量、方法、代码块、内部类。
常见形式:
1234567891011121314public class Demo { static int count; static void hello() { System.out.println("hello"); } static { System.out.println("class init"); } static class Helper { }}
不能直接修饰 ...
Java final 关键字:从“不能改”到“安全发布”的深入理解
Java final 关键字:从“不能改”到“安全发布”的深入理解前言final 是 Java 里非常常见的关键字。它看起来简单:不能改、不能继承、不能重写。但真正写项目、看源码、准备面试时,会发现 final 不只是“加个限制”,它还和代码设计、对象不可变、线程安全、JVM 优化都有关系。
可以先用一个比喻理解它:final 像给某个位置贴上封条。封条贴在哪里,限制就发生在哪里。贴在变量上,变量不能换指向;贴在方法上,方法不能被重写;贴在类上,类不能被继承。
一、final 的核心定义1.1 final 到底限制了什么final 可以修饰:
变量:变量只能赋值一次。
成员变量:必须在对象构造完成前完成初始化。
静态变量:通常用于定义常量。
方法:子类不能重写。
类:不能被继承。
方法参数:方法内部不能重新给参数赋值。
一句话总结:
final 限制的是“绑定关系”或“继承扩展点”,不是一定让对象本身不可变。
这句话很重要。比如:
123final List<String> list = new ArrayList<>();list.add(" ...
设计模式 · 享元模式(Flyweight Pattern)java
设计模式 · 享元模式(Flyweight Pattern)java前言在实际开发中,我们经常会遇到一种情况:系统里有大量对象,但这些对象中很多数据是重复的。
比如:
12345游戏地图中有 10 万棵树:每棵树都有坐标、颜色、纹理、树种。秒杀系统中有很多活动查询:每次查询都有活动名称、活动描述、开始时间、结束时间、库存信息。
随着业务规模的扩张,这些海量的对象会像无底洞一样吞噬系统的内存,导致频繁的垃圾回收(GC),甚至引发系统崩溃(OOM)。
对于这种情况,如何用最少的资源办最多的事?
如果每次都创建一个完整的对象,就像每个学生都要一本完全一样的教材,但学校却给每个人重新打印一遍,这显然会浪费大量资源。
共享元模式就是为了解决这种“重复对象过多,内存浪费严重”的问题。
其核心思想是:
相同的内容共享,不同的外部内容形成。
本文代码:https://github.com/likerhood/CodeDesignWork/tree/main/codedesign10.0-0 和 10.0-1
一、核心定义享元模式的核心思想非常纯粹:运用共享技术,有效地支持大量细粒度对象的复 ...









