Java 动态代理深度解析:从"为什么"到"底层原理"
Java 动态代理深度解析:从”为什么”到”底层原理”前言你有没有思考过一个问题:在 MyBatis 中,你只写了一个 UserMapper 接口,从来没有写过它的实现类,却可以直接调用 userMapper.selectById(1) 查出数据库结果?
这背后隐藏的技术叫做 JDK 动态代理,它是 Java 反射机制的核心应用之一,也是 MyBatis、Spring AOP、RPC 框架的基石。本文将从”为什么需要它”出发,逐步深入到底层字节码原理,并附上可运行的完整代码。
本文运行代码链接:https://github.com/likerhood/CodeDesignWork/tree/main/codedesign0.0-0/src/main/java/com/likerhood/design/mybatisproxy
一、为什么需要动态代理?1.1 先从一个真实问题说起你每天都在用 MyBatis,但有没有想过这段代码为什么能运行?
123456// UserMapper.java —— 只有接口,没有任何实现类public interface UserMapper ...
设计模式 · 适配器模式 (Adapter Pattern)
设计模式 · 适配器模式 (Adapter Pattern)前言在软件工程的实际演进中,我们经常会面临一种进退两难的局面:
系统需要引入一个非常核心的现存组件或第三方库,但它的接口标准与我们当前系统的主流架构完全不兼容。
如果我们为了迎合这个外部组件而大规模修改核心代码,不仅会打破现有的稳定性,还会造成严重的逻辑污染。
适配器模式就是为了这种“亡羊补牢”或“新老交替”的场景而生的。
它就像是一个软件层面的“扩展坞”,优雅地在不兼容的接口之间建立起一座桥梁,让系统能够无缝地复用既有资产。
本文参考博客:
本文代码链接:https://github.com/likerhood/CodeDesignWork/tree/main/codedesign5.0-0 到codedesign5.1-2都是
一、 核心定义适配器模式(Adapter Pattern) 旨在将一个类的接口转换成客户希望的另外一个接口。它使得原本由于接口不兼容而不能一起工作的那些类可以协同工作。
本质: 接口转换与兼容性适配。
分类: 主要分为“对象适配器”(基于组合机制)和“类适配器”(基于继承机制)。在 Java ...
VS Code + Claude Code 与 Codex 插件接入其他大模型详细教程
VS Code + Claude Code 与 Codex 插件接入其他大模型详细教程前言在 VS Code 中使用原生的 Claude Code 或 Codex 插件时,我们常会受限于官方的访问限制或高昂的 API 成本。
通过引入轻量级代理工具 cc-switch,我们可以极其便捷地将这些强大的 AI 编程助手重定向到 DeepSeek 等高性价比的第三方大模型。本文将详细记录完整的配置流程。
一、 核心工具下载与准备1.1 安装 VS Code 插件打开 VS Code 的扩展商店,分别搜索并安装所需的 AI 辅助插件:
Claude Code for VS Code
Codex
1.2 下载与配置 cc-switch 代理工具cc-switch 是一款带图形界面的便捷中转配置工具。
前往 GitHub 仓库地址:cc-switch/tree/main。
将页面拉到最底部的“资源包”部分,根据你的操作系统下载对应的平台安装包(如 Windows 版本)。
下载完成后解压文件夹,双击运行 cc-switch.exe。
在弹出的 UI 界面中点击 ...
Java 反射与注解的详细讲解
Java 反射与注解的详细讲解前言初学 Java SE 时,我们习惯手动 new 对象、调用方法,一切直白可控。
但进入 Spring、MyBatis 等框架后,@Autowired 自动装配依赖,@Transactional 即可生效事务……看似神奇,其实底层依然是 反射与注解的默默支撑。
一、 为什么有反射?在真正接触框架之前,很多开发者会觉得反射又慢又麻烦,直接 new 对象不好吗?
要回答这个问题,我们需要从代码的演进思维说起。
1.1 硬编码日常业务开发中,我们绝大部分代码都是硬编码。所谓硬编码,就是在写代码的时候(编译期),就已经完全确定了要使用哪个具体的类。
代码演示:
12345678910111213141516171819// 定义一个接口public interface UserService { void serve();}// 具体的实现类 Apublic class UserServiceImpl implements UserService { @Override public void serve() ...
java的运行机制:编译期、运行期和半编译半解释性
java的运行机制:编译期、运行期和半编译半解释性前言Java 的生命周期设计之所以经典,核心在于它采用了 “半编译,半解释” 的混合模式。
要真正做到“有深度”地理解 Java 的编译期和运行期,需要深入到 前端编译(javac) 和 后端编译/执行(JIT/JVM) 的底层工作流与优化策略中。
如果从程序执行模型来看,编程语言大致可以分为三类:
纯编译型语言:提前编译为机器码,运行速度极快,但跨平台能力较差;
纯解释型语言:运行时逐行解释执行,灵活性强,但性能较低;
半编译半解释型语言:先编译为中间字节码,再由虚拟机动态执行与优化。
Java 并不会像 C/C++ 那样直接编译为特定平台的机器码,而是先通过 javac 编译器将源码编译为 跨平台字节码(Bytecode),再交由 JVM(Java Virtual Machine)在不同平台上运行。
在运行过程中,JVM 又结合了:
解释执行(Interpreter)
即时编译(JIT, Just-In-Time Compiler)
两种机制。
程序启动初期通过解释执行保证快速启动;而高频运行的 ...
java的泛型(generics)详细讲解
java的泛型(generics)详细讲解前言泛型(Generics)是 Java 5 引入的一项核心特性,它本质上解决了 Java 集合在早期开发中“类型不安全”的问题。
在没有泛型的时代,集合内部统一使用 Object 存储数据,开发者不仅需要频繁进行强制类型转换,还可能在运行时因为类型错误抛出 ClassCastException。
这种问题往往隐藏很深,只有程序运行到特定场景时才会暴露出来。
泛型的出现,将类型检查从“运行时”提前到了“编译期”。 编译器能够在代码编写阶段就发现错误,从而提升程序的安全性、可读性以及可维护性。
除此之外,泛型还极大增强了代码复用能力。 无论是集合框架、工具类、并发容器,还是框架源码设计,泛型几乎贯穿了整个 Java 生态,是 Java 开发者必须掌握的重要基础。
全文测试代码链接:https://github.com/likerhood/CodeDesignWork/tree/main/codedesign0.0-0/src/main/java/com/likerhood/design/generics
一、为什么引入泛型 (Why Use ...
Java的TimeUnit详细讲解
Java的TimeUnit详细讲解前言在日常开发中,任何涉及超时、延迟、定时任务、性能统计的场景都会遇到时间单位转换问题。
你可能会写出 Thread.sleep(1000) 这样的代码,但1000代表的是毫秒吗?还是秒?如果需求变成3秒,你可能需要心算一下换算。
为了解决可读性和时间单位转换的痛点,Java从1.5版本引入的 java.util.concurrent.TimeUnit 枚举工具。
它不仅让代码更具可读性,还封装了许多实用的时间操作方法,并且**java.util.concurrent 并发包**中引入各种工具类集成。
一、TimeUnit 基础1.1 基础定义TimeUnit 是 Java 1.5 引入的一个枚举类(Enum)。顾名思义,它代表了时间单位。
它的设计初衷是为了在多线程并发编程中提供一种清晰、跨平台的时间表示方式,同时解决时间单位换算时的易错问题。
TimeUnit 涵盖了从纳秒到天的所有常用时间维度。打开源码,你可以看到它定义了以下 7 个枚举常量:
NANOSECONDS:纳秒(千分之一微秒)
MICROSECONDS:微秒(千分之一毫秒)
MIL ...
Java的String.substring() 详细讲解
Java的String.substring() 详细讲解前言在 Java 日常开发中,字符串截取是最常用的操作之一。
java.lang.String 类提供的 substring() 方法是实现这一功能的核心。
一、两种常见使用方法substring() 方法的作用是从当前字符串中提取出一个子字符串,并将其作为一个全新的 String 对象返回。
原字符串本身不会被修改(因为 Java 中的 String 是不可变的)。
它提供了两个重载版本:
1.1 单参数版本substring(int beginIndex)
功能:从指定的 beginIndex 位置开始,一直截取到字符串的末尾。
示例:
123String str = "HelloWorld";String result = str.substring(5); System.out.println(result); // 输出: World
1.2 双参数版本substring(int beginIndex, int endIndex)
功能:截取从 beginIndex 开始,到 endIndex ...
IDEA将普通目录(文件夹)重新设置为 Module(模块)
IDEA将普通目录(文件夹)重新设置为 Module(模块)前言在使用 IntelliJ IDEA 进行日常开发时,你可能遇到过以下两种令人头疼的场景:
手滑删除了模块(Remove Module): 当你在 Project 视图中选中一个 Module,右键选择了 Remove Module(或者按了 Delete 键)之后,你会发现该文件夹右下角的蓝色小方块图标消失了。此时文件和代码都还在,但 IDEA 已经不再把它当成一个完整的模块来对待了,代码提示和依赖管理全部失效。
从 Git 刚克隆下来的多模块项目: 当你开开心心地从 Git 上 clone 了一个包含多个子模块的项目并用 IDEA 打开时,IDEA 有时候会“装傻”,无法自动识别出里面的子模块。此时所有的子工程看起来都只是普通的文件夹。
下面展示如何修复。
具体操作步骤1. 打开Module设置(Open Module Setting)
第二步:在Module设置中选择Import Module找到并点击 Modules 选项。这里列出了当前项目下所有被 IDEA 识别的模块,点击加号,选择Import Modu ...
Fastjson中的JSON.parseObject()详细讲解
Fastjson中的JSON.parseObject()详细讲解前言在 Java 开发尤其是 Web 后端开发中,我们每天都在和前后端的数据交互打交道。而这其中,出场率最高、也最容易让人踩坑的 API 之一,绝对有阿里巴巴 Fastjson 库中的 JSON.parseObject()。
在使用 Fastjson(或其他 JSON 解析库)进行日常开发时,解析普通对象往往手到擒来。但一旦遇到多层嵌套的对象或泛型集合,各种 ClassCastException 就会接踵而至。
很多开发者只知道去搜一行 TypeReference 的代码贴上去解决问题,却不明白底层到底发生了什么。今天,我们就用循序渐进的实战代码,结合底层 JVM 的“类型擦除”机制,彻底弄清楚JSON.parseObject().
一、JSON.parseObject()是什么JSON.parseObject() 的本质是一个“极速翻译官”。
在互联网传输中,数据必须以**纯文本(字符串)**的形式流动,比如 {"name": "Alice", "age": ...









