覆盖实例化的 Java 对象中的方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3875666/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Overriding a method in an instantiated Java object
提问by Tyler Szabo
I would like to override a method in an object that's handed to me by a factory that I have little control over.
我想覆盖由我几乎无法控制的工厂交给我的对象中的方法。
My specific problem is that I want to override the getInputStreamand getOutputStreamof a Socket objectto perform wire logging.
我的具体问题是,我想覆盖的getInputStream和getOutputStream方法一的Socket对象进行线记录。
The generic problem is as follows:
一般问题如下:
public class Foo {
public Bar doBar() {
// Some activity
}
}
Where I'd like to take an instantiated Foo
and replace the doBar
with my own that would work as follows:
我想将一个实例化Foo
并替换为doBar
我自己的,如下所示:
Bar doBar() {
// My own activity
return original.doBar();
}
For the Socket I'm going to return an InputStreamand OutputStreamthat are wrapped by logging to intercept the data.
对于 Socket,我将返回一个InputStream和OutputStream,它们通过日志记录来拦截数据。
采纳答案by Michael Borgwardt
Since Java uses class-based OO, this is impossible. What you can do is use the decorator pattern, i.e. write a wrapper for the object that returns the wrapped streams.
由于 Java 使用基于类的 OO,这是不可能的。您可以做的是使用装饰器模式,即为返回包装流的对象编写一个包装器。
回答by Jon Skeet
You can't replace methods in existing objects - you can't change an existing object's type, for one thing.
您不能替换现有对象中的方法 - 一方面,您不能更改现有对象的类型。
You could create a new instance of another class which delegatedto the existing instance, but that has limitations too.
您可以创建委托给现有实例的另一个类的新实例,但这也有限制。
In your real world case is there no way you can simply make a separate call to wrap the streams returned by the socket? Can you give more details.
在您的现实世界中,您是否无法简单地进行单独调用来包装套接字返回的流?您能否提供更多详细信息。
回答by sjobe
I'm not sure if this is possible. Have you considered creating your own class, having the object returned by the factory as a member, and then writing the doBar() method for that class.
我不确定这是否可能。您是否考虑过创建自己的类,将工厂返回的对象作为成员,然后为该类编写 doBar() 方法。
回答by Colin Hebert
You can't really change an object on the fly in java.
在 Java 中,您无法真正动态地更改对象。
You could have something which do what you want by wrapping your Foo
into another similar objet which will delegate every call to Foo
and at the same log everything you want. (see Proxy
)
您可以通过将您的Foo
对象包装到另一个类似的对象中来做您想做的事情,该对象会将每次调用委托给Foo
您想要的所有内容并在同一日志中记录。(见Proxy
)
But if you want to do logging, maybe aspect is a better choice. (see AspectJ)
但是如果你想做日志,也许aspect是更好的选择。(见方面J)
回答by kartheek
two options:
两个选项:
- easy : if Foo were you implemetn an interface you can use a Dynamic proxyto add new functionality.
- more work: what you have is an "around" advice of AOP - you can use any of the existing AOP tools to make that possible. Spring Framework can do it for you, if you are using it already.
- 简单:如果 Foo 是您实现的接口,您可以使用动态代理来添加新功能。
- 更多工作:您拥有的是 AOP 的“周围”建议 - 您可以使用任何现有的 AOP 工具来实现这一点。Spring Framework 可以为您完成,如果您已经在使用它。
回答by Pablojim
Using a decorator is the right way to go:
使用装饰器是正确的方法:
Some very similar code to the requirement you have with sockets is here:
一些与您对套接字的要求非常相似的代码在这里:
回答by John
I think there is a way to achieve the effect you want. I saw it orriginally used in swing with buttons to allow the programmer to make the button do something when it is clicked.
我认为有一种方法可以达到您想要的效果。我看到它最初用于带有按钮的摆动,以允许程序员在单击按钮时使按钮执行某些操作。
Say you have your Foo class:
假设你有你的 Foo 类:
public class Foo {
public Bar doBar() {
// Some activity
}
}
Then you have a runner class or something similar. You can override the doBar() method at the point of instantiation and it will only affect that specific object.
然后你有一个跑步者课程或类似的东西。您可以在实例化时覆盖 doBar() 方法,它只会影响该特定对象。
that class may look like this:
该类可能如下所示:
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
}
I'm not entirely sure that will do the trick for you but maybe it'll set you in the right direction. If nothing else it is possible to override a method outside of the class, maybe that will help you.
我不完全确定这对你有用,但也许它会让你朝着正确的方向前进。如果没有其他方法可以覆盖类之外的方法,也许这会对您有所帮助。
回答by Lucas Ross
Another proxying-related solution: you could use Aspects to override a method on a given object without subclassing it yourself. This is especially appropriate and common for logging. This example uses spring-aop.
另一个与代理相关的解决方案:您可以使用 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
}
}
回答by Jose Martinez
If Socket was an interface then you could create a dynamic proxy. Below is an example. I put this here in case other people need to do this and the target instance is an instance of an interface.
如果 Socket 是一个接口,那么您可以创建一个动态代理。下面是一个例子。我把它放在这里以防其他人需要这样做并且目标实例是接口的实例。
The main reason this will not work for Socket is because java.lang.reflect.Proxy.newProxyInstance
requires an array of interfaces for its second argument, so classes won't work here. As such for this example I had to create an interface called ParentInterface
, which just has the three print methods.
这对 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");
}
}
}