Java反射-获取最高类来声明方法

问题描述 投票:0回答:1

我正在尝试获取在 java 8 中声明方法的“最高”类/接口

示例:

package pkg;

public class Classes {

    public static interface IInterface {
        void iMethod();
    }

    public abstract static class AClass implements IInterface {
        protected abstract void aMethod();
    }

    public static class SubClass extends AClass {
        
        @Override
        public void iMethod() {
            System.out.println("Sub iMethod");
        }

        @Override
        protected void aMethod() {
            System.out.println("Sub aMethod");
        }
    }
}
// getFirstDeclarator(Classes.SubClass.class, iMethod) -> AClass
// getFirstDeclarator(Classes.SubClass.class, aMethod) -> IInterface

这就是我尝试做的,只要该方法是公共的,它就可以完美工作(因为

Class#getMethod
仅适用于可访问的方法),除了它也应该适用于私有/受保护的方法

import pkg.Classes;

import java.lang.reflect.Method;

public class Main {

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

        Method iMethod = Classes.SubClass.class.getDeclaredMethod("iMethod");
        Method aMethod = Classes.SubClass.class.getDeclaredMethod("aMethod");
        System.out.println(getFirstDeclarator(Classes.SubClass.class, iMethod));
        System.out.println(getFirstDeclarator(Classes.SubClass.class, aMethod));

    }

    /**
     * Get the declaring class or interface of a method.
     * If the method is overridden, this method will return the highest superclass or interface that declares it.
     */
    public static Class<?> getFirstDeclarator(Class<?> startClass, Method method) {

        Class<?> superClass = startClass.getSuperclass();
        if (superClass != null) {
            try {

                // The problem is here: Class#getMethod only works for accessible methods
                superClass.getMethod(method.getName(), method.getParameterTypes());

                return getFirstDeclarator(superClass, method);
            } catch (NoSuchMethodException e) {
                // The method is not declared in the superclass
            }
        }

        for (Class<?> iface : startClass.getInterfaces()) {
            try {
                iface.getMethod(method.getName(), method.getParameterTypes()); // Same problem here
                return getFirstDeclarator(iface, method);
            } catch (NoSuchMethodException e) {
                // The method is not declared in the interface
            }
        }

        return startClass;
    }
}

您知道是否有办法使其适用于不可访问的方法吗?或者还有别的办法吗?

java reflection java-8
1个回答
0
投票

是的,请使用

.getDeclaredMethods()
代替。

有 2 件事相关:

  • 您需要所有方法,而不仅仅是
    public
    /
    protected
    标记的方法。
    getDeclaredMethods()
    就是这样做的。
    getMethods()
    没有。
  • 您需要整个层次结构 - 不仅是在您要调用其
    j.l.Class
    对象的类中直接声明的方法,而且还需要其父系。
    getMethods()
    就是这样做的。
    getMethods()
    没有。
    
    
  • 你可以用 while 循环来修复它们。您继续循环,更新您使用
getDeclaredMethods()

检查的

j.l.Class
实例,直到
c = c.getSuperclass()
为空(或者,如果您愿意,可以使用
c
以避免循环查找您可能不感兴趣的对象)。
您不再见证您感兴趣的方法的那个类?无论您在上一个循环中上过什么课,都是正确的答案。更新包含“答案”的变量,直到该方法消失,然后返回该答案。

请注意,对于接口,您想要的整个概念

并不存在

。不存在“第一声明者”这样的东西。简单地说: c == Object.class

当我打电话给
interface Gun { void shoot(Person p); } interface Camera { void shoot(Person p); } class ReallyBadIdea implements Camera, Gun { @Override public void shoot(Person p) { System.out.println("Psychopathic news reporter?"); } }

时,正确答案是什么?

除非你的答案是“抛出异常”,否则你就错了。

Camera 和 Gun 都有理由声称自己是第一个声明者。选择“第一个声明的”是不正确的,因为 java 不遗余力地规定

getFirstDeclarator(ReallyBadIdea.class, ReallyBadIdea.class.getMethod("shoot", Person.class))

接口的顺序并不重要;如果你现在突然介绍说它确实如此,那就太糟糕了。从架构上来说,这是一个致命的错误。充其量你可以颁布“任意一个”,但除非你真正涉及

implements
,否则你仍然会引入顺序相关性。
您可能希望重新审视是什么让您认为您需要这个。有点X/Y 问题的味道。您有一些未知的问题(从您的问题中尚不清楚)。你想到了一个解决方案:“我知道!我只要得到第一个声明符,那会有帮助的!” ....“哦,等等,这比我想象的要困难,让我向 Stack Overflow 询问一下。”。

但是,实际上,问题在于您的方法可能是错误的,因为“第一个声明符”应该无关紧要,而且实际上甚至对于接口来说也是无法回答的。 “第一个声明者”将自己仅限于类可能是可以接受的设计。但是当涉及接口时“第一个声明符”呢?我很难想象

that

是(部分)适当解决方案的任何问题。

© www.soinside.com 2019 - 2024. All rights reserved.