覆盖实例化的Java对象中的方法

我想覆盖一个由我无法控制的工厂交给我的对象中的方法。

我的具体问题是我想覆盖Socket对象getInputStreamgetOutputStream来执行有线记录

一般问题如下:

public class Foo { public Bar doBar() { // Some activity } } 

在哪里我想采用一个实例化的Foo并用我自己的doBar替换doBar ,如下所示:

 Bar doBar() { // My own activity return original.doBar(); } 

对于Socket,我将返回一个InputStreamOutputStream ,它们通过记录来拦截数据。

由于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 } 

我不完全确定会为你做什么,但也许它会让你朝着正确的方向前进。 如果没有别的可以覆盖课外的方法,也许这会对你有所帮助。

您无法替换现有对象中的方法 – 您无法更改现有对象的类型。

您可以创建委托给现有实例的另一个类的新实例,但这也有局限性。

在你的真实世界的情况下,你是不是可以简单地单独调用来包装套接字返回的流? 你能提供更多细节吗?

使用装饰器是正确的方法:

一些与套接字要求非常相似的代码在这里:

http://www.javaspecialists.eu/archive/Issue058.html

我不确定这是否可行。 您是否考虑过创建自己的类,将工厂作为成员返回的对象,然后为该类编写doBar()方法。

两种选择:

  1. 简单:如果您实现了Foo接口,则可以使用动态代理添加新function。
  2. 更多工作:你所拥有的是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"); } } }