覆盖实例化的Java对象中的方法
我想覆盖一个由我无法控制的工厂交给我的对象中的方法。
我的具体问题是我想覆盖Socket对象的getInputStream和getOutputStream来执行有线记录 。
一般问题如下:
public class Foo { public Bar doBar() { // Some activity } }
在哪里我想采用一个实例化的Foo
并用我自己的doBar
替换doBar
,如下所示:
Bar doBar() { // My own activity return original.doBar(); }
对于Socket,我将返回一个InputStream和OutputStream ,它们通过记录来拦截数据。
由于Java使用基于类的OO,因此这是不可能的。 你可以做的是使用装饰器模式 ,即为返回包装流的对象写一个包装器。
我认为有一种方法可以达到你想要的效果。 我看到它通常用于按钮,以便程序员在点击按钮时按钮。
假设你有你的Foo课程:
public class Foo { public Bar doBar() { // Some activity } }
然后你有一个跑步者类或类似的东西。 您可以在实例化时覆盖doBar()方法,它只会影响该特定对象。
该类可能如下所示:
public class FooInstance{ Foo F1 = new Foo(){ public Bar doBar(){ //new activity } } Foo F2 = new Foo(); F1.doBar(); //does the new activity F2.doBar(); //does the original activity found in the class }
我不完全确定会为你做什么,但也许它会让你朝着正确的方向前进。 如果没有别的可以覆盖课外的方法,也许这会对你有所帮助。
您无法替换现有对象中的方法 – 您无法更改现有对象的类型。
您可以创建委托给现有实例的另一个类的新实例,但这也有局限性。
在你的真实世界的情况下,你是不是可以简单地单独调用来包装套接字返回的流? 你能提供更多细节吗?
我不确定这是否可行。 您是否考虑过创建自己的类,将工厂作为成员返回的对象,然后为该类编写doBar()方法。
两种选择:
- 简单:如果您实现了Foo接口,则可以使用动态代理添加新function。
- 更多工作:你所拥有的是AOP的“周围”建议 – 你可以使用任何现有的AOP工具来实现这一目标。 如果您已经使用Spring Framework,它可以为您完成。
你无法在java中动态更改对象。
您可以通过将Foo
包装到另一个类似的对象中来执行您想要的操作,该对象会将每个调用委托给Foo
并在同一个日志中委托您想要的所有内容。 (见Proxy
)
但是如果你想做日志记录,也许方面是更好的选择。 (见AspectJ )
另一个与代理相关的解决方案:您可以使用Aspects覆盖给定对象上的方法,而无需自己进行子类化。 这对于日志记录尤其适用且常见。 这个例子使用了spring-aop。
class Example { final Foo foo; Example(Foo original) { AspectJProxyFactory factory = new AspectJProxyFactory(); factory.setTarget(original); factory.addAspect(FooAspect.class); foo = (Foo) factory.getProxy(); } @Aspect static class FooAspect { @Before("execution(Foo.doBar())") Object beforeDoBar() { // My own activity } }
如果Socket是一个接口,那么你可以创建一个动态代理。 以下是一个例子。 我把它放在这里以防其他人需要这样做,目标实例是一个接口的实例。
这对Socket不起作用的主要原因是因为java.lang.reflect.Proxy.newProxyInstance
需要为其第二个参数提供一个接口数组,所以这里的类不起作用。 因此,对于这个例子,我不得不创建一个名为ParentInterface
的接口,它只有三种打印方法。
public class Parent implements ParentInterface { @Override public void print1() { System.out.println("parent 1"); } @Override public void print2() { System.out.println("parent 2"); } @Override public void print3() { System.out.println("parent 3"); } public static void main(String[] args) { Parent originalInstance = new Parent(); ParentInterface proxied = (ParentInterface) java.lang.reflect.Proxy.newProxyInstance( Parent.class.getClassLoader(), new Class[]{ParentInterface.class}, new ParentProxy(originalInstance)); proxied.print1(); proxied.print2(); proxied.print3(); } static class ParentProxy implements InvocationHandler { final Object realObject; public ParentProxy(Object real) { realObject = real; } @Override public Object invoke(Object target, Method m, Object[] args) throws Throwable { try { if (m.getName().equals("print2")) { print2(); return null; } else { return m.invoke(realObject, args); } } catch (java.lang.reflect.InvocationTargetException e) { throw e.getTargetException(); } } public void print2() { System.out.println("wrapper 2"); } } }