0%

LinkedList 源码深度解析(基于 JDK 8)

LinkedList 是 Java 集合框架中另一种重要的 List 实现类,基于双向链表实现,与 ArrayList 形成互补:ArrayList 擅长随机访问,而 LinkedList 擅长插入和删除操作。本文将从继承关系、链表结构、核心方法及迭代器实现等方面,全面解析 LinkedList 的工作原理。

LinkedList 核心特性与继承关系

核心特性

  • 有序性:元素按插入顺序存储,支持通过索引访问(但效率低于 ArrayList)。
  • 可重复性:允许存储重复元素和 null 值。
  • 双向链表:底层通过节点的前驱(prev)和后继(next)指针维护元素关系,无需连续内存空间。
  • 非线程安全:多线程并发修改可能导致数据不一致(需手动同步或使用并发容器)。
  • 实现 Deque 接口:支持作为队列(FIFO)、栈(LIFO)或双向队列使用,提供丰富的首尾操作方法。

继承关系

LinkedList

1
2
3
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  • 继承 AbstractSequentialList:复用了顺序访问集合的基础实现(如 getadd 等依赖迭代器的方法)。
  • 实现 List:遵循 List 接口规范,支持列表的基本操作。
  • 实现 Deque:支持双端队列操作(如 addFirstpollLast 等),可作为队列或栈使用。
  • 实现 Cloneable:支持克隆(浅拷贝,节点引用被复制,但元素对象本身不复制)。
  • 实现 Serializable:支持序列化,通过自定义 writeObjectreadObject 方法优化序列化过程。

核心结构:双向链表与节点

LinkedList 的核心是双向链表,由节点(Node)组成,每个节点包含元素值、前驱节点和后继节点的引用。

节点类(Node

1
2
3
4
5
6
7
8
9
10
11
12
private static class Node<E> {
E item; // 节点存储的元素
Node<E> next; // 后继节点引用
Node<E> prev; // 前驱节点引用

// 构造器:初始化前驱、元素、后继
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}

核心变量

1
2
3
transient int size = 0;         // 链表长度(元素数量)
transient Node<E> first; // 头节点(首元素)
transient Node<E> last; // 尾节点(末元素)
阅读全文 »

ArrayList 源码深度解析(基于 JDK 8)

ArrayList 是 Java 集合框架中最常用的 List 实现类,基于动态数组实现,支持自动扩容,适用于频繁查询、少量增删的场景。本文将从继承关系、核心源码、扩容机制、迭代器实现等方面,全面解析 ArrayList 的工作原理。

ArrayList 核心特性与继承关系

核心特性

  • 有序性:元素按插入顺序存储,支持通过索引访问(0 基索引)。
  • 可重复性:允许存储重复元素,也允许存储 null 值。
  • 动态扩容:底层数组容量不足时自动扩容,无需手动管理大小。
  • 非线程安全:多线程环境下并发修改可能导致数据不一致(需手动同步或使用 CopyOnWriteArrayList)。

继承关系

ArrayList

1
2
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 继承 AbstractList:复用了 List 接口的部分默认实现(如 addAllindexOf 等)。
  • 实现 List:遵循 List 接口规范,支持列表的基本操作。
  • 实现 RandomAccess:标记接口,表明支持快速随机访问(通过索引直接访问,时间复杂度 O(1)),遍历此类集合时,普通 for 循环效率高于迭代器。
  • 实现 Cloneable:支持克隆(浅拷贝)。
  • 实现 Serializable:支持序列化,可通过流传输。

核心变量解析

ArrayList 的核心功能依赖于以下变量,决定了其存储方式和扩容行为:

阅读全文 »

Spring Bean 生命周期深度解析:从初始化到销毁的完整流程

Spring Bean 的生命周期是 Spring 容器管理 Bean 的核心逻辑,涵盖 “Bean 定义加载→实例化→属性注入→初始化→使用→销毁” 全流程。每个阶段都允许开发者通过接口或注解插入自定义逻辑,而 后置处理器(BeanPostProcessor/BeanFactoryPostProcessor) 则是扩展生命周期的关键机制。从 “生命周期完整流程→核心阶段解析→后置处理器详解→实战验证” 四个维度,彻底拆解 Spring Bean 的生命周期。

Spring Bean 生命周期全景图(核心流程)

Spring Bean 的生命周期可分为 “容器初始化阶段”“容器销毁阶段”,每个阶段包含多个关键节点,严格遵循固定顺序:

graph TD
    A[容器初始化:加载BeanDefinition] --> B[调用BeanFactoryPostProcessor 修改BeanDefinition]
    B --> C[Bean实例化:调用构造器]
    C --> D[属性注入:调用setter方法]
    D --> E[Aware接口回调:BeanNameAware->BeanFactoryAware->ApplicationContextAware]
    E --> F[BeanPostProcessor前置处理:postProcessBeforeInitialization]
    F --> G["初始化回调:@PostConstruct->InitializingBean->init-method"]
    G --> H[BeanPostProcessor后置处理:postProcessAfterInitialization]
    H --> I[Bean就绪:容器初始化完成,可使用Bean]
    I --> J[容器销毁触发]
    J --> K["销毁回调:@PreDestroy->DisposableBean->destroy-method"]

容器初始化阶段:Bean 的创建与初始化

容器初始化阶段是 Bean 从 “定义” 到 “就绪” 的核心过程,每个节点都有明确的职责和触发时机。逐阶段解析:

1. 阶段 1:BeanFactoryPostProcessor 调用(容器级后置处理)

  • 触发时机:Spring 容器加载完所有 BeanDefinition(Bean 的元数据)后,Bean 实例化前(此时仅解析配置,未创建任何 Bean 实例)。
  • 核心作用:修改 BeanDefinition 的配置(如动态修改属性值、添加依赖),扩展容器功能。
  • 实现方式:实现 BeanFactoryPostProcessor 接口,重写 postProcessBeanFactory 方法。
代码对应与输出
1
2
3
4
5
6
7
8
// 容器后置处理器实现
@Component
class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("BeanFactoryPostProcessor#postProcessBeanFactory");
}
}
阅读全文 »

SQL 关系分类与语言分类详解

SQL(结构化查询语言)是操作关系型数据库的标准语言,其体系可从关系类型语言功能两个维度进行分类。理解这些分类有助于清晰把握 SQL 的核心功能和应用场景。

SQL 关系分类(数据存储形式)

SQL 中涉及的 “关系” 本质上是二维表结构,根据存储方式和生命周期可分为三类:

1. 表(Table):物理存储的基础关系

  • 定义:数据库中永久存储的二维表,包含行(记录)和列(字段),是数据的物理载体。

  • 特性:

    • 独立存在于数据库中,数据持久化存储在磁盘上。
    • 支持 INSERTUPDATEDELETE 等操作修改数据。
    • 结构由 CREATE TABLE 定义,可通过 ALTER TABLE 修改。
  • 示例:

    1
    2
    3
    4
    5
    -- 创建表(物理存储)
    CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL
    );

2. 视图(View):逻辑定义的虚拟关系

  • 定义:由 SELECT 查询定义的虚拟表,不实际存储数据,仅保存查询逻辑,使用时动态计算结果。

  • 特性:

    • 数据依赖于基础表(视图的数据源),基础表数据变化会实时反映到视图。
    • 可简化复杂查询(将多表关联逻辑封装为视图),并限制用户访问范围(如隐藏敏感字段)。
    • 支持 SELECT 操作,部分视图可通过 INSERT/UPDATE/DELETE 修改(需满足特定条件,如基于单表且包含主键)。
  • 示例:

阅读全文 »

Spring 依赖注入(DI)详解:从原理到实践

依赖注入(Dependency Injection,简称 DI)是 Spring 框架的核心特性之一,是控制反转(IoC)思想的具体实现。它通过容器自动管理对象之间的依赖关系,替代了传统代码中手动创建依赖对象的方式,大幅降低了代码耦合度。本文从 “DI 核心概念” 到 “两种注入方式实战”,系统解析 Spring DI 的工作原理与最佳实践。

DI 与 IoC:理解核心概念

1. 传统开发的痛点:主动依赖导致高耦合

在没有 DI 的时代,对象需要主动创建其依赖的对象,导致代码耦合严重,难以维护和测试:

1
2
3
4
5
6
7
8
9
10
public class Person {
// 主动创建依赖对象,耦合度高
private Car car = new Car();
private House house = new House();

// 业务逻辑依赖于具体的 Car 和 House 实现
public void goOut() {
car.drive(); // 直接依赖 Car 实例
}
}

问题:若 Car 构造器变化(如新增参数),Person 类必须修改;更换 Car 实现(如从 Benz 改为 BMW),需修改 Person 代码。

2. 控制反转(IoC):反转依赖的创建权

IoC 核心思想:将对象的创建和依赖管理交给容器,对象只需 “被动接收” 依赖,无需主动创建。

  • 传统方式:对象 → 主动创建依赖(正转控制);
  • IoC 方式:容器 → 主动注入依赖给对象(反转控制)。

Spring 中,IoC 容器(如 BeanFactoryApplicationContext)是实现者,负责:

  • 管理对象的生命周期(创建、初始化、销毁);
  • 解析对象之间的依赖关系;
  • 在对象需要时自动注入依赖。

3. 依赖注入(DI):IoC 的具体实现

DI 是 IoC 的一种具体表现形式:容器在实例化对象时,自动将其依赖的对象注入进来,对象无需关心依赖的来源和创建过程。

阅读全文 »