ProgrammingBackend Developer

Explain how method resolution order works with method overloading and overriding in Java inheritance, and what pitfalls may arise.

Pass interviews with Hintsage AI assistant

Answer.

In Java, method overloading and overriding are resolved according to specific rules. During overloading, the compiler selects the most appropriate method from all versions at compile time based on the argument types at the call site.

Important points:

  • When overloaded methods are present in all classes and superclasses, the highest possible matches are sought first in the current class, then in superclasses.
  • The method selection occurs at compile time, not at runtime.
  • Type conversions (widening, autoboxing, varargs) are applied when necessary.

Example:

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

Here, print(Integer) will be called for an argument of type Integer, while the parent method will be called for type Double.

Trick question.

If a method is overridden and overloaded in the subclass, which one will be called during polymorphism?

Answer: In polymorphism, the version of the method is always chosen based on the actual type of the object for overridden methods. For overloaded methods, the selection is made at compile time based on the reference type.

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); // Calls B:Number, despite the existence of test(Integer)

Examples of real errors caused by ignorance of the topic's nuances.


Story

A developer added an overloaded version of a method in the subclass, expecting it to be called for all inherited classes. In production, it became clear that calls through the parent class reference led to method selection based on reference type rather than object type. As a result, the necessary logic was not executed.


Story

In a large project, they mistakenly overloaded the equals(Object) method with the signature equals(MyClass obj), thinking it would replace the standard equals. When compared in HashSet collections, the default equals(Object) was used, leading to logic mismatches and data loss.


Story

When adding a new varargs version of a method to the class hierarchy, it seemed that the necessary version would be called for arrays. However, when passing an array explicitly, the compiler selected the wrong overload, resulting in incorrect processing and the bug remained unnoticed for a long time.