在没有公共接口的情况下调用公共方法

时间:2019-04-23 06:04:13

标签: java reflection

我有一些生成的代码(即无法更改),看起来像这样。

class Generated1 {
    public String getA() {
        return "1";
    }

    public void setB(String b) {
    }

    public void setC(String c) {
    }

    public void setD(String d) {
    }
}

class Generated2 {
    public String getA() {
        return "2";
    }

    public void setB(String b) {
    }

    public void setC(String c) {
    }

    public void setD(String d) {
    }
}

我正在通过反思探索这些对象。它们都没有实现任何通用接口,但是有很多接口,我想将它们视为实现了它们。

interface CommonInterface {
    String getA();

    void setB(String b);

    void setC(String c);

    void setD(String d);
}

当然应该有可能。这被认为是非常好的代码

class CommonInterface1 extends Generated1 implements CommonInterface {
    // These are perfectly good classes.
}

class CommonInterface2 extends Generated2 implements CommonInterface {
    // These are perfectly good classes.
}

我想寻找的东西是这样的:

private void doCommon(CommonInterface c) {
    String a = c.getA();
    c.setB(a);
    c.setC(a);
    c.setD(a);
}

private void test() {
    // Simulate getting by reflection.
    List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
    for (Object object : objects) {
        // What is the simplest way to call `doCommon` with object here?
        doCommon(object);
    }
}

我的问题:我如何对待一个没有implementinterface但实际上具有所有代码的对象,就像它确实实现了接口一样

我要替换

private void doCommon(Generated1 c) {
    String a = c.getA();
    c.setB(a);
    c.setC(a);
    c.setD(a);
}

private void doCommon(Generated2 c) {
    String a = c.getA();
    c.setB(a);
    c.setC(a);
    c.setD(a);
}

...

使用

private void doCommon(CommonInterface c) {
    String a = c.getA();
    c.setB(a);
    c.setC(a);
    c.setD(a);
}

我知道我可以像这样使用Proxy,但我真的更喜欢使用更好的东西。

private void test() {
    // Simulate getting by reflection.
    List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
    for (Object object : objects) {
        // What is the simplest way to call `doCommon` with object here?
        doCommon(adapt(object));
    }
}

private CommonInterface adapt(Object o) {
    return adapt(o, CommonInterface.class);
}

public static <T> T adapt(final Object adaptee,
                          final Class<T>... interfaceToImplement) {
    return (T) Proxy.newProxyInstance(
        adaptee.getClass().getClassLoader(),
        interfaceToImplement,
        // Call the equivalent method from the adaptee.
        (proxy, method, args) -> adaptee.getClass()
            .getMethod(method.getName(), method.getParameterTypes())
            .invoke(adaptee, args));
}

4 个答案:

答案 0 :(得分:2)

如果使用反射,则不需要两个CommonInterfaceX类,可以使用实现CommonInterface的代理:

public class Wrapper implements InvocationHandler {
    private final Object delegate;

    public static <T> T wrap(Object obj, Class<T> intf) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf},
                        new Wrapper(obj));
        return intf.cast(proxy);
    }

    private Wrapper(Object delegate) {
        this.delegate = delegate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Method dmethod = delegate.getClass().getMethod(
                method.getName(), method.getParameterTypes());
        return dmethod.invoke(delegate, args);
    }
}

您可以按如下方式使用此类:

List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
    CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
    doCommon(proxy);
}

更新:请注意,同一Wrapper类可用于任何接口。

答案 1 :(得分:0)

无法在Generated1Generated2之间实现静态类型关系。

即使您创建了CommonInterface1CommonInterface2,您也仍然无法将Generated1对象静态地用作CommonInterface1,因为new Generated1() < strong> 不是 ({永远不会成为一个)CommonInterface1

到目前为止,最简单的解决方案是更改代码生成,以将CommonInterface添加到Generated1Generated2中。

如果这绝对不可能,那么避免这种代码重复的另一种方法就是反思。

答案 2 :(得分:0)

您可以通过反射手动进行操作。

MERGE

输出为

public class Generated {
    public String getA() {
        return "A";
    }

    public String sayHello(String name) {
        return "hello " + name;
    }
}

public class Helper {
    private static final String METHOD_NAME = "getA";
    private static final String METHOD_WITH_PARAM_NAME = "sayHello";

    public static void main(String[] args) throws Exception {
        Generated generated = new Generated();

        accessMethod(generated);
        accessMethodWithParameter(generated);
    }

    private static void accessMethod(Generated g) throws Exception {
        Method[] methods = g.getClass().getDeclaredMethods();
        for(Method method : methods) {
            if(isCommonMethod(method)) {
                String result = (String) method.invoke(g);
                System.out.println(METHOD_NAME + "() = " + result);
            }
        }
    }

    private static boolean isCommonMethod(Method m) {
        return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
    }

    private static void accessMethodWithParameter(Generated g) throws Exception {
        Method[] methods = g.getClass().getDeclaredMethods();
        for(Method method : methods) {
            if(isCommonMethodWithParameter(method)) {
                String result = (String) method.invoke(g, "Max");
                System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
            }
        }
    }

    private static boolean isCommonMethodWithParameter(Method m) {
        return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
                m.getReturnType().equals(String.class) &&
                m.getParameterTypes().length == 1 &&
                m.getParameterTypes()[0].equals(String.class);
    }

}

答案 3 :(得分:-2)

如果要替换为注释。我认为您可以轻松做到

首先,您创建界面CommonInterface

interface CommonInterface {
    String getA();

    void setB(String b);

    void setC(String c);

    void setD(String d);
}

然后,您创建2个类Generated1Generated2继承了CommonInterface

class Generated1 implements CommonInterface {
    @overide
    public String getA() {
        return "1";
    }

    @overide
    public void setB(String b) {
    }

    @overide
    public void setC(String c) {
    }

    @overide
    public void setD(String d) {
    }
}

class Generated2 implements CommonInterface {

    @overide
    public String getA() {
        return "2";
    }

    @overide
    public void setB(String b) {
    }

    @overide
    public void setC(String c) {
    }

    @overide
    public void setD(String d) {
    }
}