Java多态方法调用优先级为:①this.方法名(参数)→②super.方法名(参数)→③this.方法名((父类)参数)→④super.方法名((父类)参数),结合编译期签名匹配与运行时动态绑定,覆盖仅发生在签名完全一致前提下。

Java 中的多态方法调用不是“看引用类型”,而是“看实际对象类型 + 编译期可识别的方法签名 + 运行时动态绑定”的综合结果。覆盖(override)和接口默认方法的优先级,本质上是编译器和 JVM 协同解决“该调哪个方法”问题的一套明确规则,不是凭经验猜测。
覆盖方法的调用优先级:从本类开始逐层向上查找
当通过某个引用调用一个方法时,JVM 按以下顺序匹配候选方法(不考虑重载解析阶段):
- this.方法名(参数类型):先在当前对象的实际运行时类(即 new 出来的那个类)中查找完全匹配签名的方法;找到则直接调用(即使该方法是子类自己定义、父类没有的)
- super.方法名(参数类型):若未找到,再到直接父类中查找同签名方法;注意:此处 super 是静态指定的父类,不是泛指所有祖先
- this.方法名((父类)参数):若仍无匹配,尝试将实参强制转型为父类类型,再回到当前类中查找接受该转型后类型的重载版本
- super.方法名((父类)参数):最后才在父类中查找接受转型后参数类型的方法
关键点:覆盖只发生在方法签名完全一致的前提下;而上面四步本质是重载解析(compile-time)与动态分派(run-time)的结合——前两步决定“选哪个重载”,后两步决定“是否需要转型”,最终执行时仍按实际对象类型触发 override 绑定。
类继承 vs 接口默认方法:类优先原则
当一个类既继承了父类,又实现了含默认方法的接口,且两者存在同名同签名方法时:
- 父类中定义了该方法(无论是否被子类覆盖),则忽略接口的默认方法,走继承链逻辑
- 父类中没有该方法,但接口提供了默认实现,则子类自动获得该默认方法(相当于隐式继承)
- 若子类自己实现了该方法,无论父类或接口是否存在同名方法,都以子类实现为准
例如:class C extends B implements I,B 和 I 都有 void m(),则 C 实例调用 m() 一定执行 B 的版本(或 C 自己重写的版本),不会跳到 I 的 default 方法。
多个接口默认方法冲突:必须显式覆盖
当一个类同时实现多个接口,且这些接口提供了同名同签名的默认方法时:
- 编译器会报错:“
class C inherits unrelated defaults for m() from types I1 and I2” - 解决方式只有唯一一种:在类 C 中显式提供该方法的实现
- 如果想复用某接口的默认逻辑,可用语法
I1.super.m()或I2.super.m()显式调用
这个设计避免了“钻石继承”歧义,也强制开发者对冲突行为作出明确选择,而不是让 JVM 猜意图。
接口间继承的默认方法覆盖规则
接口也可以继承其他接口(支持多继承)。当子接口继承多个父接口,且它们含有同名默认方法时:
- 子接口必须用
default关键字重写该方法,不能仅靠继承 - 重写时可调用任一父接口的默认实现,如
I1.super.m() - 抽象方法重复无影响;但默认方法重复就必须处理,否则编译失败
这保证了接口层级的契约清晰性——子接口必须对所有继承来的默认行为给出确定性声明。

















