Java 8反射:如何获取方法的最高声明类或接口?
问题:获取Java方法的最高声明类/接口
我需要在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
我自己实现的代码仅对public方法有效,因为Class#getMethod仅支持可访问方法,我需要让它同样适用于private/protected方法,请问有可行方案吗?
我的现有代码:
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)); } /** * 获取方法的声明类或接口。如果方法被重写,返回声明该方法的最高父类或接口。 */ public static Class<?> getFirstDeclarator(Class<?> startClass, Method method) { Class<?> superClass = startClass.getSuperclass(); if (superClass != null) { try { // 问题所在:Class#getMethod 仅适用于可访问方法 superClass.getMethod(method.getName(), method.getParameterTypes()); return getFirstDeclarator(superClass, method); } catch (NoSuchMethodException e) { // 父类中未声明该方法 } } for (Class<?> iface : startClass.getInterfaces()) { try { iface.getMethod(method.getName(), method.getParameterTypes()); // 同样的问题 return getFirstDeclarator(iface, method); } catch (NoSuchMethodException e) { // 接口中未声明该方法 } } return startClass; } }
解决方案
问题核心在于Class#getMethod只会查找public方法(包括继承来的),无法处理protected/private方法。要解决这个问题,我们需要改用Class#getDeclaredMethod获取当前类声明的所有方法(无论访问修饰符),同时判断该方法是否属于可被重写的范畴(private方法无法被重写,无需追踪)。
修改后的实现代码如下:
import pkg.Classes; import java.lang.reflect.Method; import java.lang.reflect.Modifier; 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)); // 输出 class pkg.Classes$AClass System.out.println(getFirstDeclarator(Classes.SubClass.class, aMethod)); // 输出 interface pkg.Classes$IInterface } /** * 获取方法的最高声明类或接口。如果方法被重写,返回声明该方法的最顶层父类/接口。 */ public static Class<?> getFirstDeclarator(Class<?> startClass, Method method) { // 先处理父类链 Class<?> superClass = startClass.getSuperclass(); if (superClass != null && !Object.class.equals(superClass)) { try { // 获取父类中直接声明的同名同参数方法 Method superMethod = superClass.getDeclaredMethod(method.getName(), method.getParameterTypes()); // 排除private方法(无法被重写) if (!Modifier.isPrivate(superMethod.getModifiers())) { return getFirstDeclarator(superClass, method); } } catch (NoSuchMethodException e) { // 父类无对应方法,跳过 } } // 再处理接口链 for (Class<?> iface : startClass.getInterfaces()) { try { // 接口方法默认都是public,直接用getMethod查找 iface.getMethod(method.getName(), method.getParameterTypes()); return getFirstDeclarator(iface, method); } catch (NoSuchMethodException e) { // 接口无对应方法,跳过 } } // 无更高层声明,返回当前类 return startClass; } }
关键修改说明
- 父类处理:用
getDeclaredMethod替代getMethod,获取父类所有直接声明的方法,同时通过Modifier.isPrivate排除无法被重写的private方法。 - 终止条件:父类遍历到
Object.class时停止,避免无意义递归。 - 接口处理:接口方法均为public,保留
getMethod逻辑即可,无需额外修改。
修改后,无论是protected还是public方法,都能正确找到其最高层的声明类/接口。
内容的提问来源于stack exchange,提问作者crazycat256
相关产品推荐
相关产品推荐

