jdk动态代理为什么只能为接口生成代理类?

JDK动态代理采用接口而非继承实现,原因在于生成的代理类默认继承了`Proxy`类。由于Java单继承特性,目标对象需通过实现接口进行代理。代理类中注入了`InvocationHandler`,代理方法调用时实际执行`invoke()`方法,允许自定义逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jdk动态代理是基于接口实现的代理,而非继承

要对一个类进行扩展,无非就是继承或者是实现接口两种方式,为什么jdk的代理类,一定要基于接口实现?
直接先说结论:之所以必须要使用继承,是因为jdk为我们生成的代理类,默认继承了proxy类,所以,我们只能实现目标接口

打印代理类

jdk动态代理,是需要有一个InvocationHandler接口的实现类,在实现类中,我们可以通过Proxy.newProxyInstance()来生成代理类
Proxy.newProxyInstance()方法,最终会调用到

java.lang.reflect.Proxy.ProxyClassFactory#apply

来生成代理对象,调用链比较简单,就不再叙述了
在这个方法中,我们可以发现,有一行至关重要的代码

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);

就是这里,生成了代理类,然后再调用了一个native方法,最后返回了一个class对象,那我们可以在代码中,设置属性,把这个代理类打印出来

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

只需要这一行代码,就可以打印当前的代理类信息

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.sun.proxy;

import com.design.demo.proxy.dynamic.Sale;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Sale {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;

    public $Proxy0(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 void saleBook() throws  {
        try {
            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"));
            m3 = Class.forName("com.design.demo.proxy.dynamic.Sale").getMethod("saleBook");
            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());
        }
    }
}

这个代理类,我们可以发现,默认是继承了Proxy类,由于Java是单继承,所以,对于要代理的对象,我们只能通过实现接口的方式来实现

通过对代理类的分析,我们可以发现,在代理类中注入了一个InvocationHandler对象,这个invocationHandler对象,就是我们自己的实现类,因为我们在调用 Proxy.newProxyInstance()方法的时候,需要指定一个invocationHandler对象,所以,在我们调用目标方法(saleBook)的时候,其实会调用到invocationHandler的invoke()方法,我们可以在invoke方法中,进行自定义逻辑的处理

结论

所以,一句话解释为什么jdk动态代理必须要通过接口实现,是因为jdk在底层生成代理对象的时候,就默认继承了Proxy类,所以只能通过接口的方式,来对目标方法进行代理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值