如何复制java.lang.reflect.Method?

时间:2016-05-05 17:39:57

标签: java reflection

我有一个API,它接收$ javap -c IntegerIncrementTest.class Compiled from "IntegerIncrementTest.java" public class SO37056714.IntegerIncrementTest { public SO37056714.IntegerIncrementTest(); Code: 0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V 4: return public static void main(java.lang.String[]); Code: 0: iconst_1 1: istore_1 2: iconst_3 3: istore_2 4: iload_1 5: iload_2 6: iadd 7: istore_1 8: return } 并存储它以便稍后调用。为了调用它,我必须Method。在我这样做之前,我想做一个防御性的副本。但是如何?

我想到了

setAccessible(true)

但是在桥接方法存在的情况下(或者两种方法具有相同名称/参数类型但返回类型不同的其他情况),这不一定会给我相同的方法。

我可以遍历method.getDeclaringClass() .getDeclaredMethod(method.getName(), method.getParameterTypes()); 并寻找完全匹配,但这似乎效率低下。

一个例子说明了为什么防御性副本可能会很好:

method.getDeclaringClass().getDeclaredMethod()

Method method = ...; // Does setAccessible(true) MyInvoker invoker = new MyInvoker(method); // Sometime later, the user uses the same Method rather than re-retrieving it method.setAccessible(true); method.invoke(...); method.setAccessible(false); // Oops, now MyInvoker is broken 返回不同方法的示例:

getDeclaredMethod()

对我来说,打印:

interface Iface {
    Object get();
}

class Impl implements Iface {
    @Override
    public String get() {
        return "foo";
    }
}

for (Method method : Impl.class.getDeclaredMethods()) {
    System.out.println(method);
    System.out.println(copy(method));
    System.out.println();
}

private Method copy(Method method) {
    try {
        return method.getDeclaringClass()
                .getDeclaredMethod(method.getName(), method.getParameterTypes());
    } catch (ReflectiveOperationException e) {
        throw new RuntimeException(e);
    }
}

1 个答案:

答案 0 :(得分:1)

你必须做你最初建议的事情,并依赖于Method#equals(Object)的合同

  

将此Method与指定对象进行比较。如果,则返回true   对象是一样的。如果它们是两个Method是相同的   由同一个类声明并具有相同的名称和形式参数   类型和返回类型。

因此您将无法使用getDeclaredMethod(String, Object...)方法。您必须对Method[]返回的getDeclaredMethods()进行数组查找。例如,

private Method copy(Method method) {
    Class<?> clazz = method.getDeclaringClass();
    for (Method declaredMethod : clazz.getDeclaredMethods()) {
        if (declaredMethod.equals(method)) {
            return declaredMethod; // return the new one
        }
    }
    throw new RuntimeException("This should not happen.");
}