JDK动态代理为什么只能代理有接口的类

JDK动态代理为什么只能代理有接口的类,第1张

JDK动态代理为什么只能代理有接口的类

一、概述

最近写的东西大多都是面试中遇到的(最近在面试),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去实现。

总结:很多人认为问这些问题是没有意义的,但是我认为越往上走对计算机的基础和底层知识的理解越重要,上层的框架随着业务发展而变化,而底层的基础原理和设计理念是不会变化的。底层基础是对一个事物的本质认识,而不是停留在表面上。所以我认为掌握基础就可以以不变应万变。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/906266.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-15
下一篇 2022-05-15

发表评论

登录后才能评论

评论列表(0条)

保存