Java动态代理超详细解析:三步+内存图(堆栈分析)
0.本文适合谁?
1.刚学Java动态代理,被Proxy
、InvocationHandler
绕晕的同学
2.想彻底搞懂代理对象在内存中如何工作的开发者
3.需要面试突击动态代理知识的求职
1.动态代理的本质(三步走)
动态代理的核心可以拆解为三个关键步骤:
(1)🔹 第一步:代理类持有目标对象引用
public class Person implements InvocationHandler {private Object target; // ⭐关键!代理类持有目标对象public Person(Object target) {this.target = target;}
}
内存状态:
(2) 🔹 第二步:获取目标类方法
public Object invoke(Object proxy, Method method, Object[] args) {// method就是目标类的核心方法(如zf())return method.invoke(target, args);
}
方法调用栈:
[栈帧]
invoke(proxy, Method(zf), args)
└── ZF.zf("小白","小黑",100.00) // 真实调用
(3) 第三步:调用目标方法
proxy.zf("小白","小黑",100.00);
// 实际执行流程:
// 1. 调用$Proxy0.zf()
// 2. 转发给handler.invoke()
// 3. 最终调用ZF.zf()
2.完整内存模型
🔵 方法调用时(栈堆联动)
proxy.zf("小白","小黑",100.00);
3.执行流程
-
栈帧1:
main()
调用proxy.zf()
-
栈帧2:
$Proxy0.zf()
被调用(动态生成的代理方法) -
栈帧3:
Person.invoke()
执行拦截逻辑 -
栈帧4:最终调用
ZF.zf()
4.完整的代码+运行结果
(1)接口定义 IZF.java
/*** 转账接口(抽象主题)*/
public interface IZF {void zf(String name1, String name2, double money);
}
(2)真实实现类 ZF.java
/*** 真实转账类(真实主题)*/
public class ZF implements IZF {@Overridepublic void zf(String name1, String name2, double money) {System.out.println(name1 + "向" + name2 + "转账" + money + "元");}
}
(3)代理处理器 Person.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** 代理处理器(实现InvocationHandler)*/
public class Person implements InvocationHandler {private Object target; // 持有目标对象引用(关键点1)public Person(Object target) {this.target = target;}/*** 生成代理对象(关键点2)*/public Object getProxy() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this // 传入InvocationHandler);}/*** 方法拦截(关键点3)*/@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("【代理前置操作】记录日志");Object result = method.invoke(target, args); // 调用真实方法System.out.println("【代理后置操作】更新余额");return result;}
}
(4)测试类 Test.java
/*** 测试动态代理*/
public class Test {public static void main(String[] args) {// 1. 创建真实对象IZF realObj = new ZF();// 2. 创建代理处理器(传入真实对象)Person handler = new Person(realObj);// 3. 获取代理对象(必须用接口接收!)IZF proxy = (IZF) handler.getProxy();// 4. 通过代理对象调用方法proxy.zf("小黑", "小白", 100.00);}
}
实现结果: