Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Java method overloading lets a class declare multiple methods with the same name but different parameter lists. For each call, the compiler uses the method name, argument expressions, and applicable conversion rules to select a declaration; if there is no unique most-specific candidate, compilation fails. The return type alone cannot distinguish overloads.

What method overloading means

Overloaded methods share a name and differ in their parameters, such as parameter types or number of parameters. A class can therefore offer one name for related operations while accepting different kinds of input.

static String label(int value) { return "number"; }
static String label(String value) { return "text"; }

label(3);       // selects label(int)
label("three"); // selects label(String)

Each call is resolved at compile time from the invocation and the methods accessible in that context. The Java Language Specification (Java SE 17, §15.12) describes the compiler finding potentially applicable and applicable methods, then selecting the most specific applicable method when one exists: JLS §15.12.

How Java chooses an overload

Java does not simply pick the method whose parameter looks closest, nor does it try every possible conversion. Invocation conversions are limited by the rules in the specification. In particular, narrowing conversions are not generally allowed just because they would make an argument fit; the relevant conversion contexts are described in JLS Chapter 5, Java SE 26.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Overload resolution tests applicability in ordered phases. A candidate found in an earlier phase can take precedence over one that would only apply in a later phase.

  1. Strict invocation: tests applicable fixed-arity methods without boxing, unboxing, or variable-arity invocation.
  2. Loose invocation: permits boxing and unboxing, but still does not use variable-arity invocation.
  3. Variable-arity invocation: considers variable-arity methods after the fixed-arity phases have been tried.

A varargs declaration can participate as a fixed-arity candidate in the earlier phases when the call supplies an argument matching its array parameter. It is only treated as variable arity in the later phase. The ordering and candidate rules are specified in JLS §15.12.

Example: fixed arity before varargs

static void send(Object value) { }
static void send(String... values) { }

send("hello");

The call is applicable to send(Object) in an earlier fixed-arity phase. The varargs method is also a fixed-arity candidate when its array parameter is considered, but a single String is not a String[]; its variable-arity applicability is reached only later. The earlier applicable fixed-arity method is selected. This illustrates why “varargs is considered immediately” is inaccurate.

Specificity and conversion examples

Consider pick(long) and pick(Integer) called with an int expression. Widening the primitive int to long can make the first method applicable in the strict phase. Boxing the value to Integer is permitted in the loose phase, which is considered only if the earlier phase does not yield an applicable method. This result follows from these exact signatures and phase ordering; it is not a universal rule that every widening conversion beats every boxing conversion.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When several methods are applicable in the winning phase, Java applies specificity rules to determine whether one declaration is more specific than the others. If no unique most-specific method exists, the invocation is ambiguous and the program does not compile.

Why an overloaded call can be ambiguous

A lambda expression can be compatible with more than one functional-interface parameter type. In its JDK 21 release notes, Oracle illustrates an ambiguity involving overloads that accept Consumer<Integer> and IntConsumer: JDK 21 Release Notes. This is an example of the general overload-resolution rules, not a new rule that applies only to JDK 21.

Related ambiguity can occur with null. For example, if a class declares handle(String) and handle(Integer), then handle(null) can match both reference parameters, and neither parameter type is more specific than the other. The call is ambiguous. If instead the overloads are handle(Object) and handle(String), the String parameter is more specific, so handle(null) selects handle(String).

  • Use an explicitly typed expression or cast when the intended overload is clear but the argument is ambiguous, for example handle((String) null).
  • For public APIs, consider whether lambda-based or null calls are likely. If overloads make common calls unclear, a distinct method name may communicate intent better.

Can you overload a method by changing only its return type?

No. Two methods with the same name and identical parameter types cannot be declared as separate overloads just because their return types differ. The return type is not a valid distinguishing parameter signature for an overload declaration. The compiler uses the invocation’s arguments and the overload rules to choose a declaration; it does not generally select an overload based on the type a caller expects the expression to produce.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Overloading versus overriding

Overloading and overriding are different mechanisms. Overloading is the compile-time choice among methods with the same name and different parameter lists. Overriding occurs when a subclass provides an implementation of an inherited instance method with the same signature; after a declaration is selected for an instance call, run-time dispatch can invoke the overriding implementation.

For example, if a variable has static type Base but refers to a Child object, overload resolution uses the methods available through the call’s static context and argument expressions. If the selected instance method is overridden in Child, the child’s implementation can run. The object’s run-time class does not choose between overloads with different parameter lists.

Does the expected result type affect overload resolution?

In general, overload resolution is independent of an invocation’s target type—the type expected by the surrounding expression. The compiler does not pick a method because its return type better matches the assignment or return context. Lambdas, method references, and generic type inference have additional interactions with applicability and type inference, so those cases require applying the detailed JLS rules rather than treating the expression’s eventual result type as a general tie-breaker. See JLS §15.12.

Designing clear overloads

Overloads are most useful when the same operation has natural variations in input. Before adding one, check how the alternatives behave for parameter type and arity, which conversion phase makes each applicable, and whether one candidate is more specific. Also consider whether calls involving lambdas or null could become ambiguous. If the alternatives represent meaningfully different actions rather than variations of one action, separate method names can make the API easier to understand.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.