getDeclaredMethods只返回当前类字节码methods[]数组中显式声明的方法,不包含继承自父类或接口的任何方法,无论访问修饰符如何;它精准反映源码中该类“亲手编写”的方法。

getDeclaredMethods 只返回当前类**显式声明**的方法,不包含从父类或接口继承的任何方法,哪怕父类方法是 public 或被子类重写过 —— 它只看“源码里这一行是不是写在这个类里”。
它到底“声明”在哪儿?看字节码层面的定义
Java 规范中,“declared” 指的是方法是否在该类的 ClassFile 结构中直接出现在 methods[] 数组里。编译器不会把父类方法复制进子类的 class 文件,所以即使子类没重写 Object.toString(),这个方法也不会出现在 SubClass.class.getDeclaredMethods() 的结果中。
例如:
-
class A { void m1() {} }→A.class.getDeclaredMethods()包含m1 -
class B extends A { void m2() {} }→B.class.getDeclaredMethods()只有m2,没有m1(哪怕m1是public) -
class C extends B { @Override void m1() {} }→C.class.getDeclaredMethods()同时包含m1和m2(因为重写后,m1的字节码确实出现在C.class的 methods 表中)
和 getMethods 的关键区别:可见性 ≠ 声明位置
getMethods() 返回的是当前类及其所有父类、实现接口中所有 public 方法(包括继承来的),但前提是它们能被当前类“触及”——即访问修饰符允许(如 protected 父类方法在同包子类中可被 getMethods 返回)。
而 getDeclaredMethods() 完全无视访问控制:它会返回当前类中声明的 private、protected、package-private 和 public 方法,只要源码里写了,就一定在结果里。
典型对比:
class X { private void f() {} void g() {} }-
X.class.getDeclaredMethods()→[f, g](两个都在) -
X.class.getMethods()→[g, toString, equals, hashCode, ...](只有g是本类 public,其余全是继承自Object的 public 方法)
获取“本类独有逻辑”的真实场景
实际开发中,getDeclaredMethods 最常用于需要精准识别“这个类自己加了哪些行为”的场景,比如:
- 序列化框架扫描
@JsonIgnore、@JsonProperty等仅标注在本类方法上的注解(父类标注的不归这里管) - Mock 工具(如 Mockito)构造代理时,只拦截子类自己声明的方法,避免误覆写父类关键逻辑
- 权限校验中间件检查 Controller 类中是否标记了
@PreAuthorize,且只关心当前类写的,不关心父类 Controller 的通用逻辑 - 代码生成工具提取模板方法模式中的钩子方法(
protected abstract doXxx()),这些方法只在抽象基类中声明,子类不重写就不出现 —— 正好靠getDeclaredMethods精准定位
想同时拿到本类 + 父类方法?得手动递归
Java 反射本身不提供“本类及直接父类声明方法”的快捷 API。如果需要,必须自己遍历:
- 先调用
clazz.getDeclaredMethods() - 再调用
clazz.getSuperclass(),非null则继续取其getDeclaredMethods() - 注意:接口方法需额外处理
clazz.getInterfaces(),且接口中的默认方法(default)属于接口的declared方法,但static接口方法不算实例方法,按需过滤 - 重复方法名+签名可能多次出现(如多层继承重写),是否去重、按什么优先级(子类优先?父类优先?)需业务决定
这种组合逻辑不是反射的职责,而是上层框架根据语义做的封装 —— getDeclaredMethods 始终保持纯粹:只回答“这个类的 .java 文件里,你亲手写了哪几个方法”。

















