【问题标题】:Simple way to find method 'parents' at runtime?在运行时查找方法“父母”的简单方法?
【发布时间】:2016-08-21 09:08:01
【问题描述】:

我正在尝试找到一种简单的方法来在运行时检索方法的“父级”。 (可能使用反射)方法的“父母”是指在继承树中首先定义所述方法的类。理想情况下,这也适用于泛型。

例子:

public interface Class1<O> {
    void doSomething(O s);
}

public interface Class2 {
    void doSomething(String s);
}

public class Class3 implements Class1<String>, Class2 {
    public void doSomething(String s) {
        // Something
    }
}

如果我想获得 Class3#doSomething 的“父母”,它应该在此处检索 Class1 和 Class2。 Java中是否存在这样的方法,甚至有可能吗?

【问题讨论】:

  • 这只是指定接口,我也想要抽象类,但它可能是我找到有用的东西的一个很好的垫脚石,感谢链接。
  • 如果C从其祖父A实现了一个方法,它应该归因于A还是它的父B谁没有声明或实现该方法?
  • 到继承树中首先定义方法的任何类。
  • 您是只对被覆盖的方法感兴趣还是对任何具有相同签名的方法(例如staticprivate 方法)感兴趣?

标签: java


【解决方案1】:

参考这个question 它在接口上循环:for (Class&lt;?&gt; c : cls.getInterfaces()) ... 您还可以使用 for (Class&lt;?&gt; c : cls.getClasses()) 循环访问类

【讨论】:

    【解决方案2】:

    实现有点繁琐,但您应该能够拿起您需要的东西(前提是它可以满足您的需求)并将其余的扔掉。基本上,我们在有问题的类中找到方法,如果没有找到我们返回(如果你想搜索父母,即使类本身没有声明,那么继续搜索并且不返回)。然后我们递归直接超类树直到我们到达Object。之后根据我们的发现,我们分道扬镳寻找超级接口。

    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class TestParent {
    
        public static void main(String[] args) {
            // prints Class1 and Class2
            System.out.println(getParents(Class3.class, "doSomething"));
    
            // prints Class5
            System.out.println(getParents(Class3.class, "run"));
        }
    
        private static List<Class> getParents(Class<?> type, String methodName) {
            Method method = getMethodByName(type, methodName);
            if (method == null)
                return Collections.emptyList();
    
            Class nextClass = type.getSuperclass();
            Class parent = null;
    
            while (!nextClass.equals(Object.class)) {
    
                if (hasMethod(nextClass, methodName, method)) {
                    parent = nextClass;
                }
    
                nextClass = nextClass.getSuperclass();
            }
    
            List<Class> parents = new ArrayList<>();
    
            if (parent != null) {
                // search parent interfaces
                for (Class t : parent.getInterfaces()) {
                    if (hasMethod(t, methodName, method)) {
                        parents.add(t);
                    }
                }
    
                if (parents.isEmpty())
                    parents.add(parent);
    
            } else {
                // search our interfaces
                for (Class t : type.getInterfaces()) {
                    if (hasMethod(t, methodName, method)) {
                        parents.add(t);
                    }
                }
            }
    
            return parents;
        }
    
        private static boolean equalMethod(Method m1, Method m2) {
            return m1.getName().equals(m2.getName()) && m1.getReturnType().equals(m2.getReturnType());
            // uncomment if parameter types must be the same
            //&& Arrays.equals(m1.getParameterTypes(), m2.getParameterTypes());
        }
    
        private static boolean hasMethod(Class<?> type, String methodName, Method method) {
            Method m = getMethodByName(type, methodName);
    
            return m != null && equalMethod(method, m);
        }
    
        private static Method getMethodByName(Class<?> type, String methodName) {
            for (Method m : type.getDeclaredMethods()) {
                if (m.getName().equals(methodName)) {
                    return m;
                }
            }
    
            return null;
        }
    
        public interface Class1<O> {
            void doSomething(O s);
        }
    
        public interface Class2 {
            void doSomething(String s);
        }
    
        public class Class3 extends Class4 implements Class1<String>, Class2 {
            public void doSomething(String s) {
                // Something
            }
    
            @Override
            void run() {
    
            }
        }
    
        public abstract class Class4 extends Class5 {
            abstract void run();
        }
    
        public abstract class Class5 {
            abstract void run();
        }
    }
    

    【讨论】:

    • 很好的解决方案,但由于某种原因,相等的参数类型似乎不适用于泛型,这很糟糕,因为我认为在运行时方法 Class1#doSomething 接受“对象”参数。你认为这是 java 的限制吗?
    • 啊哈,我刚刚发现,对于泛型,类中加载了 2 个方法,一个带有“Object”参数,一个带有“String”参数。很好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-26
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多