Overriding a method in an instantiated Java object

2019-03-14 07:52发布

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 getInputStream and getOutputStream of a Socket object to perform wire logging.

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:

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

For the Socket I'm going to return an InputStream and OutputStream that are wrapped by logging to intercept the data.

9条回答
贪生不怕死
2楼-- · 2019-03-14 08:29

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.

查看更多
做个烂人
3楼-- · 2019-03-14 08:31

Using a decorator is the right way to go:

Some very similar code to the requirement you have with sockets is here:

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

查看更多
\"骚年 ilove
4楼-- · 2019-03-14 08:31

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.

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.

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");
        }

    }

}
查看更多
登录 后发表回答