Java Method Overloading
Offer related input forms under one useful method name. Learn to predict which declaration a call selects, recognize calls the compiler cannot choose between, and keep convenience methods consistent through delegation.
Before you start: review method declarations and results, arguments and parameters, and numeric conversions. All source examples use the Java 21 runner. Predict the selected declaration before running.
What you will be able to do
- Distinguish overloads by parameter count, types, and type order.
- Explain why changing a return type or parameter name does not create an overload.
- Trace overload selection using the compile-time argument types.
- Recognize widening, missing narrowing conversions, and ambiguous calls.
- Handle null calls deliberately without assuming every reference overload is distinguishable.
- Delegate a convenience overload to a core implementation and test both contracts.
One operation can have several input forms
A caller may know just a course name, or a course name together with a lesson count. Both requests produce a course label, so related methods can reasonably share the name courseLabel. Java calls this overloading: several methods have the same name but different parameter lists.
The one-argument call selects the String parameter method. The two-argument call selects the String, int method. Java does not run both and choose whichever result looks right. The compiler identifies an applicable method for the particular call before the selected body executes.
Overload related operations, not unrelated actions that happen to accept different inputs. A name should keep one recognizable meaning across the family. All examples here use static methods in one class so you can focus on overload selection rather than inheritance or instance dispatch.
Main.java · Different numbers of inputs
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Course: SQL
Course: SQL (3 lessons)
Parameter types distinguish overloads; return types alone do not
For these ordinary non-generic methods, distinguish a method by its name and ordered parameter types. A different parameter count or a different type at a position can create another overload. Changing only a parameter's variable name does not: int minutes and int duration describe the same parameter type.
Changing only the return type also does not create a new overload. You cannot declare both int doubleValue(int value) and double doubleValue(int value) in this class. The input lists are identical, and the compiler rejects the duplicate rather than using the receiving variable's type to decide which you meant.
Modifiers such as static or final are not a way to distinguish otherwise identical parameter lists either. More advanced generic signatures have additional rules, but this lesson deliberately stays with ordinary parameters. Read a declaration's input types first instead of assuming any visible textual difference is a valid overload.
Start with the types of the supplied arguments
The literal 5 has type int, 5.0 has type double, and 5L has type long. With int and double overloads, the first two calls have direct matching parameter types. The long argument cannot implicitly narrow to int, but it can widen to double, so the third call selects the double overload.
The compiler reasons about types, not whether the current numeric value happens to fit a smaller range. It does not treat 5L as an int simply because five is small. A long-to-double widening is allowed, although very large long values can lose precision; selecting an applicable overload does not guarantee exact numeric representation.
Trace a call by listing its argument types, then eliminate incompatible parameter lists. If multiple methods remain, Java applies its specificity and applicability rules. The simple examples here use fixed-arity primitives and references; boxing, varargs, and generics add further phases and should not be reduced to a universal guess about the closest-looking method.
Main.java · int and double arguments choose different overloads
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
int overload
double overload
double overload
Trace the long literal 5L
- The expression 5L has type long.
- The int overload would require an implicit narrowing, so it is not applicable here.
- The double overload accepts a long through widening.
- The double body executes and returns its identifying label.
Now replace 5L with a double variable containing 5.0. Explain why numeric equality with five does not turn that expression into an int argument.
Type order matters, but swapping names does not
entry(String, int) and entry(int, String) are different ordered type lists. The two calls demonstrate which position contains the label and which contains the count. The compiler can distinguish them because the argument types at those positions differ.
By contrast, entry(int first, int second) and entry(int second, int first) would have the same int, int type list and could not coexist as separate overloads. Parameter names do not supply named-argument dispatch. A same-typed argument swap can still compile while asking the wrong domain question.
Supporting both input orders is not always a useful design choice. It can make an interface harder to remember without adding real convenience. Use a consistent order when possible, and introduce a second form only when callers gain a clear benefit rather than merely to demonstrate that Java permits it.
Main.java · Parameter type order can differ
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Label first: Practice / 3
Count first: 3 / Practice
Delegate a shorter overload to the complete one
The one-argument formatMinutes supplies the default label Study and calls the two-argument version. This keeps the punctuation, unit suffix, and main formatting policy in one place. The caller can use the shorter form without making every call repeat the same label.
This is an ordinary method call with an explicitly supplied second argument, not a default parameter declaration. Java selects the two-argument overload because the delegation provides two arguments. return then forwards that String result back through the one-argument method to its own caller.
Avoid copying the full implementation into each overload when the behavior should stay aligned. Also avoid accidental self-calls: writing return formatMinutes(minutes) inside that same one-argument method would repeatedly call itself rather than reach the core formatter. The lab extends this delegation pattern with one shared validation policy.
Main.java · A convenience overload delegates
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Study: 25 min
Practice: 25 min
Widening can make an overload applicable without an exact match
The widening example has long and double overloads but no int overload. An int argument can widen to either long or double. In this fixed-arity primitive pair, the long overload is more specific because long can widen to double, whereas double cannot widen to long. The int call therefore selects long.
This does not mean Java inspects the value and chooses the smallest container that can hold it. The input is still an int regardless of whether its value is seven or two billion. Changing the variable's declared type to double changes the available conversions and the selected method.
Do not memorize an all-purpose slogan such as exact, then smallest, then anything else. Java overload resolution has defined applicability phases and specificity rules. Learn these small primitive cases, inspect the actual argument types, and keep overload families simple enough that a reader can predict their behavior without a puzzle.
Main.java · A compatible primitive can widen
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
long overload
double overload
A fitting constant does not gain every narrowing conversion at a call
Although seven fits into a byte, the literal 7 is an int argument. Method invocation does not automatically narrow that int constant to the byte parameter. With byte and long overloads, the ordinary call selects long through widening.
The explicit cast (byte) 7 changes the argument expression's type to byte and selects the byte overload. A byte variable initialized with seven would also supply a byte argument. Assignment contexts can allow some constant narrowing that method calls do not, so those two situations should not be treated as identical.
A cast is not a harmless request to choose a favorite method. Narrowing another value can discard information. Use a cast only when its conversion and resulting value are genuinely intended, not to suppress an ambiguous or incompatible call without understanding why the declarations are confusing.
Main.java · A fitting int literal is not implicitly a byte argument
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
long overload
byte overload
Overload selection uses compile-time reference types
Object is a broad reference type that can hold a reference to a String; the classes lessons will explain that relationship more fully. In Object value = "Mina", the variable expression value has compile-time type Object even though the object it identifies is a String.
describe(value) selects describe(Object). The String literal and the explicitly String-typed cast select describe(String). The cast is safe here because the example established the stored value as a String; casting an arbitrary Object to String could fail at runtime. Do not use casts as a substitute for an appropriate contract.
The untyped null call in this particular family chooses String because String is more specific than Object. Overload selection is not the same mechanism as overriding an inherited instance method, which is a later topic. In particular, the runtime object does not cause Java to reconsider these static overloads after the call has been selected.
Main.java · The declared reference type matters
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Object overload
String overload
String overload
String overload
Change the variable type, not its text
Change Object value to String value while keeping the text Mina. The first call now selects the String overload because the argument expression's compile-time type changed. The stored text did not need to change.
Some valid-looking calls have no single best overload
The crossed pair accepts int, long or long, int. selectPair(1, 2) supplies int, int, so either overload could accept one widening conversion. Neither candidate is more specific across both positions: each keeps a different int position exact. The compiler reports an ambiguous call instead of selecting the first method written in the file.
The runnable example states intent with 2L in the first call and 1L in the second. For int, long only the first overload is applicable without an invalid narrowing, and the reverse holds for long, int. These literals describe intended argument types; they are not a general recommendation to patch every ambiguous API with casts.
When real callers repeatedly need this disambiguation, consider whether separate descriptive method names or a simpler parameter design would be clearer. Declaration order, parameter names, and the type of the receiving String variable do not resolve this ambiguity.
Main.java · Make a crossed numeric call unambiguous
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
int, long overload
long, int overload
Reproduce the ambiguity deliberately
Change the first call to selectPair(1, 2), then Run. Both crossed declarations can accept that int, int pair, but neither wins across the full input list. Restore the intended long literal to make the example compile again. Rearranging method declarations would not repair it.
null can reveal a confusing reference overload family
String and int[] are unrelated reference types. A bare null can be passed to either describe(String) or describe(int[]), with no more-specific choice between them in this family. describe(null) is therefore ambiguous here, unlike the earlier Object and String pair.
The runnable calls type the null as String or int[] to make the intended operation explicit. The casts do not create an object or turn missing input into usable data. Each selected helper still needs a null policy; these examples return a missing-value description instead of dereferencing null.
Overloading should make common calls easier to understand, including error and missing-input cases. Two unrelated same-arity reference overloads may be legal declarations yet awkward for nullable callers. Use different names if those operations do not share a clear meaning, rather than teaching callers that any cast which compiles must be the right one.
Main.java · Type a null argument when the intent is known
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
String missing
Array missing
Compare typed and bare null
Remove the String cast from the first call, leaving describe(null). The String and int[] overloads are unrelated, so the compiler cannot select one. Restore the cast when that String intent is genuine. The helper still receives null; the cast does not create usable text.
Repair exercise: change the inputs, not only the result
This class tries to overload doubleValue by return type alone, so it cannot compile. Repair the second declaration to accept a double input, preserving both integer and fractional calls. Do not truncate the 3.5 argument to make it fit.
This is intentionally a compilation-error exercise. Run it to inspect the duplicate-method diagnostic, then repair the declaration before expecting numeric output.
Main.java · Repair duplicate input lists
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Reveal the explained repair
The broken declarations both have the input list int, so the differing result types cannot distinguish them. Changing the second input type to double creates a legal overload and preserves the fractional argument. The int call returns 6, and the double call returns 7.0. Merely changing a parameter name or casting 3.5 to int would not implement the intended two input forms.
Main.java · Repaired integer and double overloads
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
6
7.0
Independent lab: two formatting overloads, one contract
Build two related formatting overloads: one for a duration with a default label, and one for a caller-supplied label. Keep one shared validation and formatting policy. These helpers return text without reading input, printing, or saving study data.
- Declare static String formatMinutes(int minutes) and static String formatMinutes(int minutes, String label). Keep both inside Main but outside main.
- The one-argument overload must delegate to the two-argument overload with the label Study. Do not duplicate validation or formatting inside it.
- The core overload accepts any nonnegative int minutes value. Return Invalid minutes. for a negative value before checking the label.
- Then return Invalid label. when the label is null or blank. For accepted input strip only surrounding label whitespace and preserve its remaining spelling and capitalization.
- For accepted input return LABEL: N min, with the stripped label and the exact integer duration. Zero is valid, and the unit stays min for all values.
- Keep println calls only in main. Demonstrate both overloads, zero minutes, a padded label, a negative duration, a null label, and a blank label. Test repeated calls for consistent results.
The solution demonstrates the default label, a supplied label, zero minutes, surrounding whitespace, and three invalid calls. Edit the calls in source; no standard input is required. Expected output:
Study: 45 min
Practice: 45 min
Study: 0 min
Review: 30 min
Invalid minutes.
Invalid label.
Invalid label.
Main.java · Build your formatting overloads
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Hints before the solution
Make the shorter method return formatMinutes(minutes, "Study"). In the core method, return the negative-minutes message first, then guard a null or blank label. Use strip only after that guard. Finally return the formatted text without printing.
The two declarations have different argument counts, so the two-argument call with null can select its one applicable declaration. Keep that overload-selection question separate from the selected method's validation of the label value.
Reveal the explained lab solution
Main.java · Formatting-overloads solution
Predict the result, edit Main.java, then run your program.
Standard input · optional
Select Run code to compile and execute this program.
Argument count distinguishes these overloads, so a null second argument is not ambiguous in this family. The shorter overload supplies Study, then returns the core overload's result. The core checks minutes first, then label, and applies one formatting rule. Both valid and invalid results return to main, which performs all output. An error string is a deliberate small-example contract, not an exception or a valid duration; a larger application might choose a structured validation result later. No arithmetic is needed to format the int, so even Integer.MAX_VALUE is accepted without overflow.
Test changes and boundaries
Edit the source calls and compare returned text, not just whether compilation succeeds. Reset restores the sample. Equivalent default and explicit-label calls should remain aligned, including invalid-minute behavior.
- Run the supplied calls and compare all seven lines with the expected output. The helpers themselves must produce no extra console messages.
- Compare formatMinutes(45) with formatMinutes(45, "Study"). They must return identical text, including spacing and punctuation.
- Try 0, 1, and 2147483647. All are valid and keep the unit min. Negative values return Invalid minutes. in either overload.
- Try a null label, a blank label, and a label with surrounding spaces. Only the valid label is stripped and formatted. If minutes and label are both invalid, Invalid minutes. takes precedence.
- Change the default label in the convenience call from Study to Focus and predict which examples change. Leave the core policy untouched; explicit labels must still behave the same way.
Common mistakes and how to diagnose them
method is already defined
Check the method name and ordered parameter types. Return type, parameter names, and modifiers alone do not create another overload. The compiler rejects duplicate input lists even when the implementations differ.
reference to a method is ambiguous
More than one candidate may accept the arguments without one best choice. Inspect crossed primitive lists or unrelated nullable reference types. Make genuine type intent explicit or simplify the overload family; do not rely on declaration order.
A small numeric value selects an unexpected overload
Inspect the expression's type: 5, 5L, 5.0, and a byte variable are not interchangeable. Invocation does not perform every constant narrowing that assignment permits. Value range alone does not choose an overload.
An Object variable containing a String selects Object
The call uses the expression's compile-time type for overload selection. An actual String object does not cause these static overloads to be reselected at runtime. Cast only when the intended type and safety are established.
The short overload keeps calling itself
Check the delegated argument list. Passing the same one argument back to the same one-argument overload recurses rather than reaching the core method. Supply the additional label as intended instead of running unbounded recursion.
Overloads disagree on validation or punctuation
The implementation may have been duplicated. Delegate the convenience overload to the core version so valid and invalid calls share one policy. Test equivalent calls and explicit labels to catch drift.
Frequently asked questions
Can return type alone select an overload?
No. Ordinary methods in this class cannot differ only by return type. Changing the receiving variable's type does not make otherwise duplicate declarations legal.
Is overloading the same as overriding?
No. Overloading uses different parameter lists and is resolved from the call at compile time. Overriding concerns inherited instance behavior, covered in later object-oriented lessons.
Does Java choose the first declared matching method?
No. Applicability and specificity determine the selected overload. If no unique choice exists, the compiler reports ambiguity rather than using source order.
Is a null argument always ambiguous?
No. It depends on the overload family. String is more specific than Object, but String and int[] are unrelated. The lab has only one two-argument overload, so its null label selects that method and is handled by validation.
Should I overload every method that could share a name?
No. Keep one clear operation meaning and consistent contracts. Separate names are often better for unrelated input forms, different units, or overload families that make ordinary calls hard to predict.
Choose the declaration from the call, then trace its body
Overloads provide related input forms with distinct parameter lists. Argument types and applicability matter; return type, parameter names, and source order do not rescue duplicate or ambiguous calls. A convenience overload should delegate when its main difference is a supplied default choice.
Before moving on, explain why 5L does not become int merely because it fits, why Object and String differ from String and int[] for null, and why the lab keeps one formatting policy. Next: scope and variable lifetime.
Can you predict which overload is selected?
Answer all six questions and read the explanations. Results are temporary on this page and do not save course progress.
References and related learning
The scenarios, explanations, examples, and exercises are original SovranCode material. Official references support the Java 21 language rules.
Review declarations and return values · Review argument types and positions · Review widening and narrowing · Java course roadmap.
Last updated: