一、概述
最近写的东西大多都是面试中遇到的(最近在面试),JDK动态代理为什么只能代理有接口的类?
这个是我在面试的时候遇到的一个问题。这个在我们的认知中就是代理接口的类,很正常的,还要问为什么。 这个正式考察你对java的底层知识的理解。
二、JDK Proxy 为什么只能代理有接口的类
这个问题的本质核心是,JDK Proxy动态代理本身的机制来决定的。
public class JdkProxy implements InvocationHandler {
//这个就是我们要代理的真实对象
private Object object;
//构造方法,给我们要代理的真实对象赋初值
public JdkProxy(Object object){
this.object = object;
}
/**
*
* @param proxy 代理对象
* @param method 代理对象调用的方法
* @param args 调用方法中的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("Before.....");
//当代理对象调用真实对象的方法时,
//会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
result = method.invoke(object,args);
System.out.println("After.....");
return result;
}
}
//代理的真实对象
JdkImpl jdkImpl = new JdkImpl();
/**
* InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用.
* 要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法
*/
InvocationHandler handler = new JdkProxy(jdkImpl);
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
Jdk jdk = (Jdk) Proxy.newProxyInstance(
JdkImpl.class.getClassLoader(),//类加载器
JdkImpl.class.getInterfaces(),//用来代理的接口
handler); //InvocationHandler 对象
一方面在java里面是Proxy.newProxyInstance()这个方法来实现的,方法中需要传入被动态代理的接口类,之所以要传入接口而不能传入类是基其器底层实现,JDK Proxy 在运行期间会动态生成一个$Proxy代理类 ,这个代理类会继承java.lang.reflect.Proxy类,同时实现被代理类的接口,在java里面是不支持多继承的,而每个动态代理类已经继承了Proxy类,这样就导致JDK动态代理只能代理接口,而不能代理实现类。
另一方面分析JDK动态代理的源码发现Proxy类只是保存了动态代理的InvocationHandler处理器,如果不抽象出来,直接编译生成到新的$Proxy代理类里面,我认为也可以,这样的话,就可以对实现类做动态代理,为什么这么设计?我认为动态代理原始的需求只是保护目标对象和增强目标对象,而实际开发模式都是面向接口开发的,所以基于接口实现从需求和场景都是符合的。因为在java 里面类的集成关系更多考虑到共性能力的抽象,从而提高代码的复用性和扩展性,而动态代理也是在做相同的事情,就是把生成代理类的抽象逻辑和InvocationHandler处理器,把这些公共逻辑放在Proxy 父类中,也是正常的设计思路。我认为技术方案的设计师解决特点场景问题的,当然确实存在没有接口的一些普通类可以选择CGLib去实现。
总结:很多人认为问这些问题是没有意义的,但是我认为越往上走对计算机的基础和底层知识的理解越重要,上层的框架随着业务发展而变化,而底层的基础原理和设计理念是不会变化的。底层基础是对一个事物的本质认识,而不是停留在表面上。所以我认为掌握基础就可以以不变应万变。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)