Methods
Method Overloading
Analyze compile-time polymorphism, overload signatures, and the compiler's strict resolution precedence rules.
Interview: Focuses on static compiler binding, precedence (Widening vs Boxing vs Varargs), and compile-time ambiguity errors.
Method Overloading allows multiple methods in the same class to share the same name but have different parameter lists. It is a form of compile-time (static) polymorphism where the compiler decides which method to invoke at compile time.
Core Idea
Overloaded methods must differ in parameter types, count, or order. Changing return types or exceptions alone is not sufficient.
Why It Matters
The compiler resolves method targets using a specific priority logic. If multiple methods match, a compile-time ambiguity error is thrown.
Interview Lens
Deeply tests resolution order: Widening -> Autoboxing -> Varargs. Expect edge cases with null arguments.
Compiler Resolution Precedence Order
When a method is invoked, the Java compiler selects the most specific overloaded signature using the following priority order:
- Exact Match: The argument types match the parameter types exactly.
- Widening (Implicit Numeric Promotion): Primitives are widened to larger primitive types (e.g.,
intis promoted tolong, then tofloat, and then todouble). - Autoboxing / Unboxing: Primitives are converted to their wrapper objects (e.g.
inttoInteger), or objects are unboxed to primitives. - Varargs: Varargs parameters are evaluated last because they have the lowest priority.
Note on Widening vs. Autoboxing: In Java, widening takes precedence over autoboxing. The compiler favors promoting an int to a long over boxing it to an Integer. This design preserves compatibility with older Java versions that did not support autoboxing.
Ambiguity Compilation Errors
Ambiguity occurs when the compiler finds multiple signatures that match a method call equally well, making it impossible to determine the intended method. For example:
void process(int a, long b) { } void process(long a, int b) { }
// Calling this method: process(10, 10); // COMPILE ERROR: Reference to process is ambiguous
Both arguments are int literals. The compiler can widen the first argument to match the second method, or widen the second argument to match the first. Since both options are equally valid, the compiler throws an ambiguity error.
Common Pitfalls
- Changing only Return Types: Expecting methods to overload by changing the return type, which causes a duplicate method signature compilation error.
- Introducing Ambiguity: Overloading methods with broad type promotions (e.g. double vs float) that result in compile-time ambiguity.
- Passing Null to Overloaded Methods: Invoking a method with
nullwhen signatures exist for bothStringandInteger, causing compile errors because both types are references.
Best Practices
- Only overload methods when they perform the same conceptual action on different data types. If the actions are different, give them different names.
- Avoid overloading methods with parameter lists that differ only by primitive widening promotions (e.g.,
intvslong). - When overloading constructors, chain them using
this()to centralize initialization logic.
Interview-Relevant Information
Q1: Why does a compiler choose a widened primitive method over an autoboxed wrapper method?
Answer: Widening (e.g. promoting int to long) has existed since Java 1.0, whereas autoboxing was introduced in Java 5. To maintain backward compatibility, the Java compiler always prioritizes primitive widening over autoboxing.
Q2: How does the compiler resolve: "void print(String s)" and "void print(Object o)" when called with "print(null)"?
Answer: It resolves to the String version. When matching overloaded methods, the compiler selects the most specific type. Since String is a subclass of Object, it is more specific, so the compiler selects the String signature.
Quick Checklist
Can you order compiler resolution steps, identify potential ambiguities, predict overrides with null references, and explain widening vs autoboxing rules? If yes, you understand method overloading.
Use Cases
Designing utility classes like Arrays.sort() with overloaded parameter types for primitives and objects.
Creating fluent API configurations with overloaded option setters.
Common Mistakes
Altering only the return type to overload a method, causing a duplicate signature error.
Relying on implicit type promotion paths that introduce compile-time ambiguity errors.