Method Overloading in Java – Rules and Examples
Method overloading means defining several methods in the same class with the same name but different parameter lists. The compiler decides which one to call by looking at the number, types and order of the arguments. Overloading is Java's form of compile-time polymorphism.
You use overloading constantly: System.out.println has overloads for int, double, String, Object and more. This tutorial covers the valid ways to overload, the exact resolution rules the compiler follows, ambiguous calls, and overloaded constructors.
1. Ways to Overload a Method
Overloaded methods must differ in their parameter list:
public class OverloadingWays {
// 1. Different number of parameters
static int sum(int a, int b) { return a + b; }
static int sum(int a, int b, int c) { return a + b + c; }
// 2. Different parameter types
static double sum(double a, double b) { return a + b; }
static String sum(String a, String b) { return a + b; }
// 3. Different order of parameter types
static String tag(String name, int id) { return name + "#" + id; }
static String tag(int id, String name) { return id + ":" + name; }
public static void main(String[] args) {
System.out.println(sum(2, 3));
System.out.println(sum(2, 3, 4));
System.out.println(sum(2.5, 1.25));
System.out.println(sum("Java", "ByTechie"));
System.out.println(tag("order", 42));
System.out.println(tag(42, "order"));
}
}
5 9 3.75 JavaByTechie order#42 42:order
| Change | Valid overload? |
|---|---|
| Number of parameters | Yes |
| Types of parameters | Yes |
| Order of parameter types | Yes (but use with care: it is easy to confuse) |
| Only the return type | No: compile error, "method is already defined" |
| Only parameter names | No |
Only access modifier, static or throws clause | No |
Generic types that erase to the same type, such as List<String> vs List<Integer> | No: "name clash: same erasure" |
2. How the Compiler Chooses an Overload
When no overload matches the argument types exactly, the compiler searches in three phases and stops at the first phase that finds a match:
- Exact match or widening of primitives (
byte → short → int → long → float → double) and subtype to supertype references. No boxing, no varargs. - Boxing and unboxing allowed (
int ↔ Integer). - Varargs allowed.
Within a phase, the most specific method wins.
public class OverloadResolution {
static void show(int x) { System.out.println("int: " + x); }
static void show(long x) { System.out.println("long: " + x); }
static void show(double x) { System.out.println("double: " + x); }
static void show(Integer x) { System.out.println("Integer: " + x); }
static void show(Object x) { System.out.println("Object: " + x); }
static void show(int... x) { System.out.println("varargs: " + x.length + " values"); }
public static void main(String[] args) {
byte b = 10;
show(b); // phase 1: widening byte -> int (exact type not available)
show(5); // exact match: int
show(5L); // exact match: long
show(5.0f); // widening float -> double
show(Integer.valueOf(7)); // exact match: Integer
show("text"); // String -> Object
show(1, 2, 3); // only varargs fits
show(); // varargs with zero arguments
}
}
int: 10 int: 5 long: 5 double: 5.0 Integer: 7 Object: text varargs: 3 values varargs: 0 values
Note how show(b) with a byte chose int (widening, phase 1) over Integer or Object (boxing, phase 2), and varargs was used only when nothing else fit.
3. Ambiguous Calls
If two overloads are equally specific, the call is ambiguous and does not compile. Passing null picks the most specific reference type:
public class AmbiguousCall {
static void print(Integer x, long y) { System.out.println("Integer, long"); }
static void print(long x, Integer y) { System.out.println("long, Integer"); }
static void find(String s) { System.out.println("String version"); }
static void find(Object o) { System.out.println("Object version"); }
public static void main(String[] args) {
// print(1, 2); // compile error: reference to print is ambiguous
print(Integer.valueOf(1), 2L); // explicit types remove the ambiguity
find(null); // String is more specific than Object -> String version
find((Object) null); // cast chooses the Object version
}
}
Integer, long String version Object version
Fix ambiguity with explicit casts or argument types, or, better, by designing overloads that cannot be confused.
4. Constructor Overloading
Constructors are overloaded the same way, giving callers several ways to create an object. Chaining them with this(...) keeps the logic in one place:
public class OverloadedConstructors {
static class Pizza {
private final String size;
private final String crust;
private final int toppings;
Pizza() { this("Medium"); }
Pizza(String size) { this(size, "Classic"); }
Pizza(String size, String crust) { this(size, crust, 1); }
Pizza(String size, String crust, int t) { this.size = size; this.crust = crust; this.toppings = t; }
public String toString() { return size + " " + crust + " pizza with " + toppings + " topping(s)"; }
}
public static void main(String[] args) {
System.out.println(new Pizza());
System.out.println(new Pizza("Large"));
System.out.println(new Pizza("Small", "Thin"));
System.out.println(new Pizza("Large", "Cheese Burst", 4));
}
}
Medium Classic pizza with 1 topping(s) Large Classic pizza with 1 topping(s) Small Thin pizza with 1 topping(s) Large Cheese Burst pizza with 4 topping(s)
See Constructors in Java and Constructor Chaining.
5. Other Overloading Facts
maincan be overloaded, but the JVM only starts the program withpublic static void main(String[] args).- Static methods can be overloaded, and a static and an instance method can overload each other if their parameter lists differ.
- Overloading across inheritance: a subclass can add an overload of a method inherited from its parent.
- Overloading is resolved at compile time using the declared types of the arguments, not their runtime types.
6. Best Practices
- Overloads should do the same thing with different inputs; different behaviour deserves a different name.
- Avoid overloads with the same number of parameters where the types are related by boxing or inheritance (
remove(int)vsremove(Object)inListis a famous trap). - Prefer distinct names (
ofSeconds,ofMinutes) or builders when many combinations exist. - Delegate from simpler overloads to the most complete one.
7. Summary
- Overloading means same method name, different parameter lists, in the same class or hierarchy.
- Return type, parameter names and modifiers alone cannot distinguish overloads.
- The compiler chooses in phases: exact/widening, then boxing, then varargs; the most specific wins.
- Ambiguous calls fail to compile; constructors are overloaded the same way.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is method overloading in Java?
Defining multiple methods with the same name but different parameter lists, so the compiler chooses the right one based on the arguments.
Q2. Can we overload a method by changing only the return type?
No. The compiler would not know which method to call when the result is ignored, so it reports "method is already defined".
Q3. Can we overload the main method?
Yes, but the JVM only calls public static void main(String[] args) to start the program. Other overloads are ordinary methods.
Q4. Can static methods be overloaded?
Yes. Static methods can be overloaded just like instance methods.
Q5. Is overloading compile-time or runtime polymorphism?
Compile-time. The method is selected by the compiler from the declared argument types.
Q6. Can we overload methods that differ only in throws clause?
No. Exceptions are not part of the method signature.
Q7. What is type promotion in overloading?
If no exact match exists, a smaller primitive is widened to a larger one (for example byte to int) to find a matching overload.
Q8. Which is preferred: widening, boxing or varargs?
Widening first, then boxing, then varargs. This order kept old code working when boxing and varargs were added in Java 5.
Q9. What happens when I pass null to overloaded methods?
The compiler chooses the most specific reference type. If two unrelated types (like String and Integer) both accept null, the call is ambiguous.
Q10. What is an ambiguous method call?
A call where two or more overloads are equally applicable and none is more specific. It causes a compile error.
Q11. Can constructors be overloaded?
Yes. A class can have several constructors with different parameter lists, often chained with this(...).
Q12. Can overloaded methods have different return types?
Yes, as long as their parameter lists also differ.
Q13. Can overloaded methods have different access modifiers?
Yes. Access modifiers do not matter for overloading; only the parameter list does.
Q14. Can a subclass overload a parent's method?
Yes. Declaring a method with the same name but different parameters in the subclass adds an overload; the parent's version is still inherited.
Q15. Why can't I overload with List<String> and List<Integer>?
Due to type erasure, both become List at run time, so the methods would have the same signature. The compiler reports a name clash.
Q16. What is the List.remove trap?
List<Integer> has remove(int index) and remove(Object o). list.remove(1) removes the element at index 1, not the value 1; use remove(Integer.valueOf(1)) for the value.
Q17. Is println an overloaded method?
Yes. PrintStream has println overloads for every primitive type, char[], String, Object and no arguments.
Q18. Does overloading depend on the runtime type of arguments?
No. Only the compile-time (declared) types matter. An Object variable holding a String still calls the Object overload.
Q19. Can varargs methods be overloaded?
Yes, but varargs overloads are chosen last and can easily lead to ambiguity, especially with zero arguments.
Q20. What are the advantages of method overloading?
A consistent name for related operations, more readable code and flexible APIs that accept different input types.