java - 对接口(interface)重写方法的反射(reflection)

标签 java generics reflection overriding

我有以下代码,一个通用的 ITest 接口(interface)由一个非通用的 ITestDouble 接口(interface)扩展。 op 方法被 ITestDouble 覆盖。

当我尝试列出ITestDouble 的所有方法时,我得到了两次op。如何验证它们实际上是相同的方法?

public class Test {

    public static void main(String[] args) throws NoSuchMethodException {
        for (Method m : ITestDouble.class.getMethods()) {
            System.out.println(m.getDeclaringClass() + ": " + m + "(bridge: " + m.isBridge() + ")");
        }
    }

    public interface ITestDouble extends ITest<Double> {
        @Override
        public int op(Double value);

        @Override
        public void other();
    }

    public interface ITest<T extends Number> {
        public int op(T value);

        public void other();
    }
}

输出:

interface Test$ITestDouble: public abstract int Test$ITestDouble.op(java.lang.Double)(bridge: false)
interface Test$ITestDouble: public abstract void Test$ITestDouble.other()(bridge: false)
interface Test$ITest: public abstract int Test$ITest.op(java.lang.Number)(bridge: false)

PS 我知道这与 Java Class.getMethods() behavior on overridden methods 是同一个问题,但这个问题没有真正的答案:isBridge() 调用总是返回 false

编辑: 我也可以接受任何会为我过滤掉“重复”op 方法的肮脏工作的库。

最佳答案

不幸的是,您无法获得该信息,因为就JVM 而言,ITestDouble 具有合法的方法op(Number),它可以完全独立于op(Double)。实际上是您的 Java 编译器 确保方法始终一致。

这意味着您可以使用完全不同的 op(Number)op(Double) 实现来创建 ITestDouble 的病态实现,方法是使用JDK5 之前的编译器或动态代理:

public static void main(String[] args) throws NoSuchMethodException {

    final Method opNumber = ITest.class.getMethod("op", Number.class);
    final Method opDouble = ITestDouble.class.getMethod("op", Double.class);
    final Method other = ITestDouble.class.getMethod("other");

    ITestDouble dynamic = (ITestDouble) Proxy.newProxyInstance(
            ITestDouble.class.getClassLoader(),
            new Class<?>[]{ITestDouble.class},
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
                    if (opDouble.equals(m)) return 1;
                    if (opNumber.equals(m)) return 2;
                    // etc....

                    return null;
                }
            });

    System.out.println("op(Double): " + dynamic.op(null);            // prints 1.
    System.out.println("op(Number): " + ((ITest) dynamic).op(null);  // prints 2. Compiler gives warning for raw types
}

编辑: 刚刚得知Java ClassMate .它是一个可以正确解析声明中所有类型变量的库。它非常易于使用:

    TypeResolver typeResolver = new TypeResolver();
    MemberResolver memberResolver = new MemberResolver(typeResolver);

    ResolvedType type = typeResolver.resolve(ITestDouble.class);
    ResolvedTypeWithMembers members = memberResolver.resolve(type, null, null);
    ResolvedMethod[] methods = members.getMemberMethods();

现在,如果您遍历 methods,您将看到以下内容:

void other();
int op(java.lang.Double);
int op(java.lang.Double);

现在很容易过滤重复项:

public boolean canOverride(ResolvedMethod m1, ResolvedMethod m2) {
    if (!m1.getName().equals(m2.getName())) return false;

    int count = m1.getArgumentCount();
    if (count != m2.getArgumentCount()) return false;

    for (int i = 0; i < count; i++) {
        if (!m1.getArgumentType(i).equals(m2.getArgumentType(i))) return false;
    }

    return true;
}

关于java - 对接口(interface)重写方法的反射(reflection),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12373607/

相关文章:

c# - 将不同类型的 Action<T> 数组传递给方法

Java泛型和 "Bound mismatch"

reflection - 如何获取Kotlin构造函数参数的KClass

c# - .Net 编译器 Hook

java - 在java中用正则表达式修改字符串电话号码

java - 容器中的JVM错误地计算处理器?

c# - 从 Java 到 C# 验证(匹配) token

java - 将列表中的所有字符串打印成单个字符串的最优雅/简洁的方法是什么?

java - 从泛型参数的构造函数中获取对象类型?

c# - 从可变字符串加载字符串类型(如可变变量和反射)