编程后端开发者

解释 Java 中继承时方法重载顺序 (method resolution order) 的工作原理,以及可能出现的陷阱。

用 Hintsage AI 助手通过面试

答案。

在 Java 中,方法的重载 (overloading) 和重写 (overriding) 根据特定规则进行解析。在重载 (overloading) 时,编译器在编译阶段根据调用时参数的类型选择最合适的方法。

重要事项:

  • 当所有类和父类都有重载的方法时,首先在当前类中查找最高匹配,然后在父类中查找。
  • 方法选择发生在编译阶段,而不是运行阶段。
  • 类型转换 (widening, autoboxing, varargs) 在必要时应用。

示例:

class Super { void print(Number n) { System.out.println("Super Number"); } } class Sub extends Super { void print(Integer i) { System.out.println("Sub Integer"); } } ... Sub s = new Sub(); s.print(5); // Sub Integer s.print(5.0); // Super Number

这里,print(Integer) 将为 Integer 类型的参数被调用,而对于 Double 类型,将调用父类的方法。

陷阱问题。

如果在子类中重写 (override) 和重载 (overload) 了一个方法,那么在多态性下将调用哪个?

回答: 在多态性下,对于重写的方法,总是根据对象的实际类型选择方法版本。对于重载的方法,选择在编译阶段基于引用的类型进行。

class A { void test(Number n) { System.out.println("A:Number"); } } class B extends A { void test(Integer n) { System.out.println("B:Integer"); } @Override void test(Number n) { System.out.println("B:Number"); } } ... A obj = new B(); obj.test(1); // 调用 B:Number, 尽管存在 test(Integer)

由于对主题细节不了解导致的实际错误示例。


故事

一位开发人员在子类中添加了一个重载版本的方法,期望它会被所有继承者调用。在生产环境中,明显通过父类引用调用的方法是根据引用的类型选择的,而不是对象。因此,所需的逻辑没有执行。


故事

在一个大型项目中,错误地重载了 equals(Object) 方法,签名为 equals(MyClass obj),以为它会替代标准的 equals。在 HashSet 集合中的比较仍然使用默认的 equals(Object),这导致逻辑不匹配和数据丢失。


故事

当在类层次结构中添加带有 varargs 的新版本方法时,似乎数组会调用所需的版本。然而,在明确传递数组时,编译器选择了错误的重载,导致处理不正确,且错误长时间未被发现。