发布时间:2026/9/2 20:32:27
java之动态代理 目录[TOC](目录)前言1. 比喻理解2. 代码理解1. 签名2. 参数1ClassLoader loader (类加载器)3. 参数2Class?[] interfaces (接口数组)4. 参数3InvocationHandler h (调用处理器)3. 测试与运行4. 代理字节码原理总结前言通过一个通俗易懂的比喻快速理解 Java 动态代理的核心设计思想。通过手写 JDK 动态代理的完整代码详细剖析其核心参数与运行机制并深入 JVM 内存中的代理类字节码揭示动态代理的底层实现原理。1. 比喻理解例子大明星小美十分擅长唱歌和跳舞。打算举办演唱会举办演唱会的过程非常繁琐。小美只想把核心精力放在唱歌和跳舞上。代理小帅专门负责处理小美唱歌和跳舞之外的所有繁杂事务。赞助商希望小美来唱歌时不能直接和小美对话必须先和经纪人小帅交涉。调用过程小帅和赞助商谈妥后前置准备把小美带到舞台上小美只管唱歌核心业务。唱完歌后小帅还要负责结算收尾工作后置收尾。在这个过程中小帅就是小美的代理人也就是我们代码中常说的代理对象。2. 代码理解我们首先写一个接口叫做Star明星声明两个方法sing和dance。publicinterfaceStar{Stringsing(StringsongName);voiddance();}小美是大明星实现Star接口擅长sing与dancepublicclassBigStarimplementsStar{OverridepublicStringsing(StringsongName){System.out.println(小美正在唱songName);return谢谢大家;}Overridepublicvoiddance(){System.out.println(小美正在跳舞);}}接下来我们编写用于创建代理对象的工具类ProxyUtil。importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassProxyUtil{publicstaticStarcreateProxy(Starstar){return(Star)Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),//参数1newClass?[]{Star.class},//参数2newInvocationHandler(){//参数3OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{if(sing.equals(method.getName())||dance.equals(method.getName())){System.out.println(找演唱会地点);Objectresultmethod.invoke(star,args);System.out.println(收尾);returnresult;}returnmethod.invoke(star,args);}});}}为了让代理对象正常工作Proxy.newProxyInstance必须明确以下三个参数1. 签名publicstaticObjectnewProxyInstance(ClassLoaderloader,Class?[]interfaces,InvocationHandlerh)2. 参数1ClassLoader loader (类加载器)在程序运行过程中动态代理会在内存中实时生成代理类的字节码。为了让 JVM 识别并加载该字节码需要提供一个类加载器。通常使用当前工具类的类加载器ProxyUtil.class.getClassLoader()或被代理类的类加载器。3. 参数2Class?[] interfaces(接口数组)此参数表示代理类要实现哪些接口。在我们的例子中代理要代替明星唱歌跳舞因此需要实现Star接口写为new Class?[]{Star.class}。4. 参数3InvocationHandler h (调用处理器)当外部调用代理对象的任何方法时都会转发到此处理器的invoke方法中执行。3. 测试与运行我们编写Main类进行测试publicclassMain{publicstaticvoidmain(String[]args){// 1. 创建真实对象BigStarbigStarnewBigStar();// 2. 创建代理对象StarproxyStarProxyUtil.createProxy(bigStar);// 3. 调用代理方法StringretproxyStar.sing(Lucky);System.out.println(ret);}}运行后控制台输出如下找演唱会地点 小美正在唱Lucky 收尾 谢谢大家4. 代理字节码原理看看代理对象的伪代码importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;importjava.lang.reflect.UndeclaredThrowableException;publicfinalclass$Proxy0extendsProxyimplementsStar{privatestaticMethodm1;// 代表 Object.equals()privatestaticMethodm2;// 代表 Object.toString()privatestaticMethodm3;// 代表 Star.sing()privatestaticMethodm4;// 代表 Star.dance()static{try{m1Class.forName(java.lang.Object).getMethod(equals,Object.class);m2Class.forName(java.lang.Object).getMethod(toString);m3Class.forName(Star).getMethod(sing,String.class);m4Class.forName(Star).getMethod(dance);}catch(Exceptione){thrownewNoSuchMethodError(e.getMessage());}}public$Proxy0(InvocationHandlerh){super(h);// 将处理器传递给父类 java.lang.reflect.Proxy}OverridepublicfinalStringsing(StringsongName){try{// 所有方法调用都会转发到超类持有的 InvocationHandler 的 invoke 方法中return(String)super.h.invoke(this,m3,newObject[]{songName});}catch(Error|RuntimeExceptione){throwe;}catch(Throwablet){thrownewUndeclaredThrowableException(t);}}Overridepublicfinalvoiddance(){try{super.h.invoke(this,m4,null);}catch(Error|RuntimeExceptione){throwe;}catch(Throwablet){thrownewUndeclaredThrowableException(t);}}}动态生成的代理类命名为$Proxy0它继承了java.lang.reflect.Proxy并且实现了目标接口Star。Java 不支持多重继承$Proxy0已经占用了继承Proxy的名额。所以只能代理接口无法代理实例化的类.$Proxy0的构造方法接收一个InvocationHandler h并通过super(h)传给父类Proxy统一保管。在重写的接口方法如sing、dance中没有包含任何业务逻辑而是直接调用super.h.invoke(this, method, args).总结动态代理的核心思想是解耦通过代理对象将繁琐的非核心业务与真实对象的核心业务隔离开来。JDK 动态代理利用java.lang.reflect.Proxy类的newProxyInstance方法在运行期动态地在内存中生成实现了指定接口的代理类字节码。代理类如$Proxy0继承自Proxy并实现目标接口其内部持有一个InvocationHandler对象所有接口方法的调用都会被重定向并转发到该处理器的invoke方法中执行。

相关新闻

2026/9/2 3:17:41

毕业必备!2026AI论文工具大盘点(覆盖 99% 毕业生论文需求)

本文精选13 款2026 年实测 AI 论文工具,按全流程全能型、垂直领域专精型、润色降重专家、文献管理助手四大类别排序,覆盖从选题到定稿全链路,适配本科 / 硕博 / 期刊全场景,附选型速查表与避坑指南,帮你快速找到最佳拍…

2026/9/2 20:31:18

电竞选手转会传闻如何验证?以stew加盟EDG爆料为例

在“瓦”这个项目里,选手阵容变动永远是最容易引发讨论的话题。一条“外媒爆料前JDG选手stew或将加入EDG,以替代jieni7参加上海冠军赛”的消息,短短几十个字里包含了选手ID、前战队、现战队、赛事名称和人员替代关系。对于普通观众来说&#…

2026/9/2 20:31:18

手柄映射实战:用pygame给战舰主题贪吃蛇打造顺滑输入体验

简介:一套基于STM32战舰V3开发板、通过手柄控制、在液晶屏上运行的贪吃蛇游戏完整工程,适合单片机初学者、电子爱好者和希望巩固外设驱动能力的嵌入式开发者。压缩包共156个文件,大小仅2.62MB,除C/H源码外,还包含Keil工…

2026/9/2 20:31:18

眼睛凝视追踪器Demo:从摄像头到屏幕坐标的眼动交互全解析

简介:《eye-tribe-tracker-demo》是一款基于Java的眼球追踪技术演示项目,面向希望了解视线捕捉原理的开发者、人机交互研究者及生物实验人员。它演示了如何调用Eye-Tribe SDK完成设备初始化、眼动数据捕获与视线轨迹绘制,帮助读者快速入门眼动…

2026/9/2 20:31:18

软件测试面试七天冲刺:高频考点与项目实战指南

先说明一下,标题里的“有点恶心”指的不是面试内容恶心,而是这套冲刺方法比较硬核:七天里需要早起背概念、白天刷题、晚上整理项目笔记,过程确实有点不舒服。但如果你正处于“学完软件测试不知道从哪复习”的状态,或者…

2026/9/2 20:31:18

ADManager Plus 7.1实战:从自动化管理到安全治理的AD运维指南

简介:本资源为ManageEngine ADManager Plus 7.1 64位正式版安装包,面向Windows Active Directory系统管理员、IT帮助台技术人员及企业合规审计人员,旨在解决AD日常运维中批量账户管理、角色权限委派、合规性报表生成及移动化用户操作等核心痛…

2026/9/2 20:26:18

Windows 7终版VSCode 1.70.3:部署配置与插件兼容指南

简介:面向仍在使用 Windows 7 且无法常规安装软件或缺少管理员权限的开发者,此压缩包提供 Visual Studio Code 1.70.3 的 64 位解压免安装版本,也是该系统可用的最后一个官方 64 位版本,无需修改注册表,解压到任意目录…

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/2 9:00:32

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/2 8:41:06

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/2 0:03:41

单片机毕业设计-基于单片机与蓝牙通讯的输液状态监测终端设计与开发 基于 STM32 或 51 单片机的液位‑滴速‑温度多参数输液监护装置设计(024005)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/9/2 0:03:41

DeepSeek字幕翻译实战:从API调用到批量SRT转中文的完整方案

这次我们来看一个很实用的 DeepSeek 落地场景:用 DeepSeek 把英文视频字幕自动翻译成中文。具体案例是《恶魔君》1989 年第 28 集的英转中字幕任务,标题写得很直白,但背后其实是一整套可以复用的技术流程:字幕解析、模型调用、批量…

2026/9/2 0:03:41

用Python搭建搞笑语音助手:从语音识别到语音合成全教程

当你家里摆着一台天猫精灵,却总希望语音助手偶尔“不正经”一点,不用官方腔回答问题,而是张口就接几句搞笑段子,会是什么体验?我最近动手验证了一下这个想法——没有去改装任何市面上现有的智能音箱,而是直…

2026/9/2 1:15:22

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/2 1:15:22

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/2 1:15:20

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…