简介
本篇文章将以两个 JDK 常见问题为引,探索介绍 JDK 动态代理的基础知识点
问题
在面试中有下面两个常见的问题,看看你是否能信心十足的回答上来,如果可以,这篇文章那不必花费时间去看
1.JDK 动态代理为啥不能对类进行代理?
2.抽象类可不可以进行 JDK 动态代理?
本人也是看文章的时候遇到这两个问题,但没有信心十足回答上来,所以有了这篇文章
JDK 动态代理的使用示例
我们先写一个简单的 JDK 动态代理示例代码,看看生成的代理类源码
源码工程 GitHub 地址:https://github.com/lw1243925457/JAVA-000/tree/main/homework/mybatis/jdkProxy
 // 接口类,定义了两个,主要是想看看两个接口的代理类情况public interface IExample {
    String hello();}
public interface IExtend {
    String hi();}
// 实现类public class ExampleImpl implements IExample, IExtend {
    @Override    public String hello() {        return "ExampleImpl hello";    }
    @Override    public String hi() {        return "hi";    }}
// 代理类public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;
    public ProxyInvocationHandler(final Object target) {        this.target = target;    }
    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("enter proxy handler");        return method.invoke(target, args);    }}
       复制代码
 
最后写一个测试类,测试输出,并保存代理类的源码,方便后面进行查看
 public class ProxyTest {
    @Test    public void test() throws IOException {        final IExample example = new ExampleImpl();        final IExample exampleProxy = (IExample) Proxy.                newProxyInstance(example.getClass().getClassLoader(),                        example.getClass().getInterfaces(),                        new ProxyInvocationHandler(example));        System.out.println(exampleProxy.hello());
        byte[] bts = ProxyGenerator.generateProxyClass("$ExampleProxy", example.getClass().getInterfaces());        FileOutputStream f = new FileOutputStream(new File("D:\\Code\\Java\\self\\JAVA-000\\homework\\mybatis\\jdkProxy\\src\\main\\resources\\$GameProxy.class"));        f.write(bts);        f.flush();        f.close();    }}
       复制代码
 
上面的运行结果也很简单:
 enter proxy handlerExampleImpl hello
       复制代码
 JDK 代理类源码
下面我们来看看测试中,保存下来的代理类源码,如下:
 public final class $ExampleProxy extends Proxy implements IExample, IExtend {    private static Method m1;    private static Method m4;    private static Method m3;    private static Method m2;    private static Method m0;
    public $ExampleProxy(InvocationHandler var1) throws  {        super(var1);    }
    public final boolean equals(Object var1) throws  {        try {            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});        } catch (RuntimeException | Error var3) {            throw var3;        } catch (Throwable var4) {            throw new UndeclaredThrowableException(var4);        }    }
    public final String hi() throws  {        try {            return (String)super.h.invoke(this, m4, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }
    public final String hello() throws  {        try {            return (String)super.h.invoke(this, m3, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }
    public final String toString() throws  {        try {            return (String)super.h.invoke(this, m2, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }
    public final int hashCode() throws  {        try {            return (Integer)super.h.invoke(this, m0, (Object[])null);        } catch (RuntimeException | Error var2) {            throw var2;        } catch (Throwable var3) {            throw new UndeclaredThrowableException(var3);        }    }
    static {        try {            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));            m4 = Class.forName("IExtend").getMethod("hi");            m3 = Class.forName("IExample").getMethod("hello");            m2 = Class.forName("java.lang.Object").getMethod("toString");            m0 = Class.forName("java.lang.Object").getMethod("hashCode");        } catch (NoSuchMethodException var2) {            throw new NoSuchMethodError(var2.getMessage());        } catch (ClassNotFoundException var3) {            throw new NoClassDefFoundError(var3.getMessage());        }    }}
       复制代码
 
可以看到,在代理类的内部其中保留被代理对象的很多引用,而在我们定义的代理类 InvocationHandler 中,保留了对原对象的引用
     static {        try {            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));            m4 = Class.forName("IExtend").getMethod("hi");            m3 = Class.forName("IExample").getMethod("hello");            m2 = Class.forName("java.lang.Object").getMethod("toString");            m0 = Class.forName("java.lang.Object").getMethod("hashCode");        } catch (NoSuchMethodException var2) {            throw new NoSuchMethodError(var2.getMessage());        } catch (ClassNotFoundException var3) {            throw new NoClassDefFoundError(var3.getMessage());        }    }
       复制代码
 
对于文章开头的两个问题,答案就在类定义上面了,不知道你们看出来了没有
 public final class $ExampleProxy extends Proxy implements IExample, IExtend
       复制代码
 
可以看到生成的代理类,默认继承了类:Proxy,实现了我们定义的两个接口:IExample, IExtend
在 Java 中,是单继承,也就是代理类已经没有办法再继承其他的类,这就是上面两个问题的答案
总结
通过实现代理类,查看代理类的源码,我们得到了开头的两个问题的答案:
1.JDK 动态代理为啥不能对类进行代理?
2.抽象类可不可以进行 JDK 动态代理?
代理对应是自动生成的,其中已固定继承了 Proxy 类,无法再对其他的类和抽象类进行继承
参考链接
评论