如何创建代理并调用默认接口方法,使其复用父类实现?
实现Bar接口代理并复用Super类方法逻辑的方案
要实现这个需求,核心是利用Java动态代理的InvocationHandler来拦截方法调用,让默认方法内部的returnSomething()调用转发到Super类的实现上。下面是具体的实现步骤和代码示例:
核心思路
- 创建动态代理实现
Bar接口,代理的InvocationHandler持有Super类的实例,用于复用其returnSomething()逻辑。 - 当调用
Bar的默认方法returnSomethingMore()时,通过MethodHandles触发默认方法的执行;此时默认方法内部的returnSomething()调用会被代理拦截,转而调用Super实例的对应方法。 - 对
Foo接口的returnSomething()方法做特殊处理,直接转发到Super实例的实现。
完整代码示例
import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 原定义的接口和类 interface Foo { default int returnSomething() { return 1; } } interface Bar extends Foo { default int returnSomethingMore() { return returnSomething(); } } class Super implements Foo { @Override public int returnSomething() { return 2; } } public class BarProxyDemo { public static void main(String[] args) { // 创建Super实例,复用它的returnSomething逻辑 Super superLogic = new Super(); // 生成Bar接口的代理对象 Bar barProxy = (Bar) Proxy.newProxyInstance( Bar.class.getClassLoader(), new Class<?>[]{Bar.class}, new BarProxyHandler(superLogic) ); // 调用默认方法,预期输出2(复用Super的returnSomething) System.out.println(barProxy.returnSomethingMore()); } // 自定义InvocationHandler处理代理方法调用 static class BarProxyHandler implements InvocationHandler { private final Super superInstance; public BarProxyHandler(Super superInstance) { this.superInstance = superInstance; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 处理默认方法:调用接口的默认实现逻辑 if (method.isDefault()) { return invokeDefaultInterfaceMethod(proxy, method, args); } // 处理Foo接口的returnSomething方法,转发到Super实例 if (method.getDeclaringClass() == Foo.class && method.getName().equals("returnSomething")) { return superInstance.returnSomething(); } // 其他未处理的方法抛出异常 throw new UnsupportedOperationException("Unsupported method: " + method.getName()); } // 调用接口默认方法的工具方法 private Object invokeDefaultInterfaceMethod(Object proxy, Method method, Object[] args) throws Throwable { MethodHandles.Lookup lookup = MethodHandles.lookup(); return lookup.findSpecial( method.getDeclaringClass(), method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()), method.getDeclaringClass() ).bindTo(proxy).invokeWithArguments(args); } } }
关键细节说明
- 默认方法调用:Java反射无法直接调用接口默认方法,所以我们用
MethodHandles.Lookup来获取并执行默认方法的逻辑,绑定的this是代理对象,这样默认方法内部的后续调用会被代理拦截。 - 方法转发逻辑:当默认方法内部调用
returnSomething()时,这个调用会进入InvocationHandler的invoke方法,我们在这里把它转发给Super实例的实现,从而复用了Super的业务逻辑。 - 类型判断:通过
method.isDefault()区分默认方法和普通接口方法,确保不同类型的方法得到正确处理。
内容的提问来源于stack exchange,提问作者Giovanni Lovato
相关产品推荐
相关产品推荐

