Java子类方法重写:如何让Child1调用Child2的mymethod?
先明确下你的核心需求:
让Child1的
run()里调用的mymethod()指向Child2的实现,不能修改Father类的mymethod(),并且要保留Child2里的逻辑——满足if条件返回true,不满足就调用Father的原方法。
完全可以做到,下面给你两种最实用的方案:
方案一:直接修改Child1(最简单的路子)
既然需求只禁止修改Father的mymethod(),那我们直接在Child1里重写mymethod(),让它委托给Child2的实现就好。因为Child2的mymethod()是protected修饰的,只要Child1和Child2在同一个包下,或者通过实例调用(子类实例能访问父类的protected方法),就能直接调用。
修改后的Child1代码如下:
public class Child1 extends Father { public void run() { mymethod(); } @Override protected boolean mymethod() { // 创建Child2实例,调用它的mymethod逻辑 return new Child2().mymethod(); } }
这样一来,Child1的run()调用mymethod()时,就会直接执行Child2里的逻辑:满足条件返回true,不满足则调用Father的原方法,完美匹配你要的流程。
方案二:不修改Child1(用动态代理绕开)
如果因为某些原因不能改动Child1的代码,那我们可以用Java的动态代理技术,在运行时拦截Child1实例的mymethod()调用,把它转去执行Child2的版本。
情况1:如果类有实现接口(JDK动态代理)
如果Child1或者它的父类Father实现了某个接口,用JDK自带的动态代理就够了:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Child1ProxyHandler implements InvocationHandler { private final Father targetChild1; private final Child2 child2Delegate = new Child2(); public Child1ProxyHandler(Father target) { this.targetChild1 = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 只拦截mymethod的调用 if ("mymethod".equals(method.getName())) { return child2Delegate.mymethod(); } // 其他方法还是用原Child1的逻辑 return method.invoke(targetChild1, args); } // 生成代理实例的工具方法 public static Father createProxy(Child1 original) { return (Father) Proxy.newProxyInstance( original.getClass().getClassLoader(), original.getClass().getInterfaces(), new Child1ProxyHandler(original) ); } }
使用的时候,不要直接用原Child1实例,改用代理后的实例:
public class Main { public static void main(String[] args) { Child1 original = new Child1(); Father proxiedChild1 = Child1ProxyHandler.createProxy(original); proxiedChild1.run(); // 这里的run会触发Child2的mymethod } }
情况2:没有实现接口(用CGLIB代理)
如果你的类没有实现任何接口,JDK动态代理就用不了,这时候可以用CGLIB来生成子类代理:
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class Child1CglibProxy implements MethodInterceptor { private final Child1 originalChild1; private final Child2 child2Delegate = new Child2(); public Child1CglibProxy(Child1 target) { this.originalChild1 = target; } public static Child1 createProxy(Child1 target) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Child1.class); enhancer.setCallback(new Child1CglibProxy(target)); return (Child1) enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { if ("mymethod".equals(method.getName())) { return child2Delegate.mymethod(); } // 其他方法调用原类的逻辑 return proxy.invokeSuper(obj, args); } }
使用方式和JDK代理类似,替换成CGLIB生成的实例即可。
这两种方案都能完美实现你要的执行流程,选哪种就看你能不能修改Child1的代码啦~
内容的提问来源于stack exchange,提问作者MarEng

