Java 不允许 super::methodName 方法引用,因为 super 是运行时关键字而非可静态解析的类型或接收者,编译器无法在编译期绑定;必须用 Lambda 包装如 () -> super.methodName()。

Java 中不能直接用 super::methodName 的方式写方法引用调用父类同名方法。
为什么 super:: 不被允许
方法引用(如 String::length)本质是函数式接口的实例化语法糖,要求目标必须是明确、可静态解析的成员方法或构造器。而 super 是一个运行时上下文关键字,代表当前对象在父类视角的引用,它不是类型也不是可独立存在的“接收者”,编译器无法在编译期将其绑定为一个稳定的方法引用目标。
简单说:super 只能在普通方法体内使用(如 super.foo()),不能作为方法引用的前缀。
替代方案:用 Lambda 显式调用 super
当需要把“调用父类方法”作为函数式逻辑传递时,唯一合规做法是用 Lambda 表达式包装 super 调用:
立即学习“Java免费学习笔记(深入)”;
- ✅ 正确写法:
() -> super.methodName()(无参) - ✅ 正确写法:
(a, b) -> super.methodName(a, b)(带参) - ❌ 错误写法:
super::methodName(编译不通过)
例如:
class Parent {
void print() { System.out.println("Parent"); }
}
class Child extends Parent {
@Override
void print() { System.out.println("Child"); }
void test() {
// ✅ 合法:用 lambda 包装 super 调用
Runnable r = () -> super.print();
r.run(); // 输出 "Parent"
// ❌ 编译错误:super::print
// Runnable r2 = super::print;
}
}
注意重写场景下的实际行为
即使你成功通过 Lambda 调用了 super.methodName(),也仅表示“在此处执行父类版本”。该调用本身不构成方法引用,不会影响多态分派逻辑——它只是普通方法调用,走的是编译期确定的父类方法字节码指令(invokespecial),和普通 super.xxx() 完全一致。
所以它不改变函数式接口的语义,也不支持像 String::length 那样被反复复用或传递为类型安全的引用;它只是一个一次性封装。
如果真需要复用父类方法逻辑
可以考虑提取成静态工具方法,或在父类中提供非重写的专用方法供子类引用:
- 在父类定义
final void parentPrint() { ... },子类用Parent::parentPrint - 把逻辑抽到工具类,如
Utils::printParentStyle - 避免在子类中依赖
super做函数式抽象,优先重构设计
本质上,Java 方法引用的设计初衷是简化对已有、明确签名方法的引用,而非解决继承链中的动态调用歧义问题。


















