Java Notes
Complete guide to method overloading in Java — compile-time polymorphism, overloading rules, type promotion, ambiguity resolution, and real-world patterns.
Method overloading means having multiple methods in the same class with the same name but different parameter lists. The compiler determines which method to call based on the arguments at compile time.
This is also called compile-time polymorphism or static polymorphism because the decision is made during compilation, not at runtime.
Why Overloading Exists
Without overloading, you'd need different names for similar operations:
// Without overloading - ugly, hard to remember
public class Calculator {
public int addTwoInts(int a, int b) { return a + b; }
public int addThreeInts(int a, int b, int c) { return a + b + c; }
public double addTwoDoubles(double a, double b) { return a + b; }
public String concatenateStrings(String a, String b) { return a + b; }
}// With overloading - clean, intuitive
public class Calculator {
public int add(int a, int b) { return a + b; }
public int add(int a, int b, int c) { return a + b + c; }
public double add(double a, double b) { return a + b; }
public String add(String a, String b) { return a + b; }
}The name add clearly communicates intent. The compiler picks the right version based on what you pass.
Rules for Valid Overloading
Methods are considered overloaded when they differ in:
| Can Differ | Example | Valid? |
|---|---|---|
| Number of parameters | add(int) vs add(int, int) | ✅ |
| Type of parameters | add(int) vs add(double) | ✅ |
| Order of parameters | add(int, String) vs add(String, int) | ✅ |
| Return type only | int add(int) vs double add(int) | ❌ |
| Access modifier only | public add(int) vs private add(int) | ❌ |
| Exception thrown only | Same params, different throws | ❌ |
Critical rule: Return type alone is NOT enough to overload!
// ❌ COMPILE ERROR - same parameters, only return type differs
public int getValue(int x) { return x; }
public double getValue(int x) { return (double) x; }
// The compiler can't decide: which one to call for getValue(5)?Complete Working Example
int: 42 double: 3.14 String: Hello Score: 95 Array: [1, 2, 3]
Type Promotion (Widening) in Overloading
When no exact match exists, Java promotes the argument to a wider type:
public class TypePromotion {
public void display(int x) {
System.out.println("int: " + x);
}
public void display(long x) {
System.out.println("long: " + x);
}
public void display(double x) {
System.out.println("double: " + x);
}
public static void main(String[] args) {
TypePromotion tp = new TypePromotion();
byte b = 10;
short s = 20;
int i = 30;
long l = 40L;
float f = 3.14f;
tp.display(b); // byte promoted to int → prints "int: 10"
tp.display(s); // short promoted to int → prints "int: 20"
tp.display(i); // exact match → prints "int: 30"
tp.display(l); // exact match → prints "long: 40"
tp.display(f); // float promoted to double → prints "double: 3.14..."
}
}int: 10 int: 20 int: 30 long: 40 double: 3.140000104904175
Overloading with Autoboxing and Varargs
Java's resolution priority (from highest to lowest):
- Exact match
- Widening primitive
- Autoboxing/unboxing
- Varargs
public class ResolutionOrder {
public void test(int x) {
System.out.println("int: " + x);
}
public void test(long x) {
System.out.println("long: " + x);
}
public void test(Integer x) {
System.out.println("Integer: " + x);
}
public void test(int... x) {
System.out.println("varargs: " + Arrays.toString(x));
}
public static void main(String[] args) {
ResolutionOrder r = new ResolutionOrder();
r.test(5); // Priority 1: exact match → int
r.test(5L); // Priority 1: exact match → long
// If we remove test(int), then test(5) → widening to long
// If we also remove test(long), then test(5) → autoboxing to Integer
// If we also remove test(Integer), then test(5) → varargs
}
}int: 5 long: 5
Constructor Overloading
Constructors can be overloaded just like methods:
public class Pizza {
private String size;
private String crust;
private List<String> toppings;
private boolean extraCheese;
// Full specification
public Pizza(String size, String crust, List<String> toppings, boolean extraCheese) {
this.size = size;
this.crust = crust;
this.toppings = new ArrayList<>(toppings);
this.extraCheese = extraCheese;
}
// Size + toppings (default crust)
public Pizza(String size, List<String> toppings) {
this(size, "Regular", toppings, false);
}
// Just size (plain pizza)
public Pizza(String size) {
this(size, "Regular", new ArrayList<>(), false);
}
// Default (medium plain)
public Pizza() {
this("Medium");
}
@Override
public String toString() {
return size + " pizza, " + crust + " crust, toppings: "
+ (toppings.isEmpty() ? "none" : toppings)
+ (extraCheese ? " + EXTRA CHEESE" : "");
}
}
public class Main {
public static void main(String[] args) {
Pizza p1 = new Pizza("Large", "Thin", List.of("Pepperoni", "Mushrooms"), true);
Pizza p2 = new Pizza("Medium", List.of("Margherita"));
Pizza p3 = new Pizza("Small");
Pizza p4 = new Pizza();
System.out.println(p1);
System.out.println(p2);
System.out.println(p3);
System.out.println(p4);
}
}Large pizza, Thin crust, toppings: [Pepperoni, Mushrooms] + EXTRA CHEESE Medium pizza, Regular crust, toppings: [Margherita] Small pizza, Regular crust, toppings: none Medium pizza, Regular crust, toppings: none
Overloading with Varargs
public class MathOperations {
// Fixed parameters
public int sum(int a, int b) {
System.out.print("(2 params) ");
return a + b;
}
// Variable arguments
public int sum(int... numbers) {
System.out.print("(varargs) ");
int total = 0;
for (int n : numbers) total += n;
return total;
}
public static void main(String[] args) {
MathOperations math = new MathOperations();
System.out.println(math.sum(5, 3)); // Fixed wins over varargs
System.out.println(math.sum(1, 2, 3)); // Varargs (3 args)
System.out.println(math.sum(1, 2, 3, 4, 5)); // Varargs (5 args)
System.out.println(math.sum()); // Varargs (0 args)
}
}(2 params) 8 (varargs) 6 (varargs) 15 (varargs) 0
Ambiguity in Overloading
Sometimes the compiler can't decide which method to call:
public class Ambiguous {
public void test(int a, long b) {
System.out.println("int, long");
}
public void test(long a, int b) {
System.out.println("long, int");
}
public static void main(String[] args) {
Ambiguous obj = new Ambiguous();
obj.test(5, 10L); // ✅ Clear: int, long
obj.test(5L, 10); // ✅ Clear: long, int
// obj.test(5, 10); // ❌ COMPILE ERROR! Ambiguous
// Both (int→int, int→long) and (int→long, int→int) are valid
}
}Real-World Example: Logging Framework
[INFO] UserService: User logged in [DEBUG] UserService: Processing request #12345 [ERROR] UserService: Failed to connect Caused by: RuntimeException: Connection timeout [INFO] UserService: User Alice performed 5 actions
Overloading in the Java Standard Library
Java uses overloading extensively:
// System.out.println() - 10 overloaded versions
System.out.println(); // void
System.out.println(int x); // int
System.out.println(double x); // double
System.out.println(String x); // String
System.out.println(Object x); // Object
// String.valueOf() - multiple overloads
String.valueOf(int i);
String.valueOf(double d);
String.valueOf(boolean b);
String.valueOf(char[] data);
String.valueOf(Object obj);
// Arrays.sort() - overloaded for each type
Arrays.sort(int[] a);
Arrays.sort(double[] a);
Arrays.sort(Object[] a);
Arrays.sort(T[] a, Comparator<? super T> c);Common Mistakes
- Thinking return type alone can overload:
``java int get() { return 1; } double get() { return 1.0; } // ❌ Compile error ``
- Confusing overloading with overriding:
- Overloading = same class, different parameters
- Overriding = child class, same parameters
- Varargs ambiguity:
``java void test(int... a) { } void test(int a, int... b) { } test(1, 2); // ❌ Ambiguous! ``
- Null ambiguity with reference types:
``java void print(String s) { } void print(Object o) { } print(null); // Calls print(String) — most specific type wins ``
- Overloading based on parameter names (doesn't work):
``java void calc(int width) { } void calc(int height) { } // ❌ Same signature! Different name doesn't matter ``
Best Practices
- Use overloading for methods that do the same logical operation on different inputs
- Keep overloaded methods consistent in behavior
- Use chaining (delegate to the most complete version)
- Don't overload with similar types that could confuse callers
- Consider Builder pattern if you have too many constructor overloads
- Document which overload is the "primary" implementation
Interview Questions
Q1: What is method overloading? Having multiple methods with the same name but different parameter lists in the same class. Resolved at compile time.
Q2: Can we overload by changing only the return type? No. The compiler determines which method to call based on arguments, not what you do with the result. Return type alone cannot distinguish methods.
Q3: Can we overload static methods? Yes. Static methods can be overloaded like any other method.
Q4: Can we overload main() method? Yes, but JVM always calls public static void main(String[] args) as the entry point. Other overloads are regular methods.
Q5: What is type promotion in overloading? When no exact match exists, Java widens the argument: byte→short→int→long→float→double. The smallest widening is preferred.
Q6: Is overloading compile-time or runtime polymorphism? Compile-time (static) polymorphism. The compiler decides which method to call based on the argument types at compile time.
Q7: Can overloaded methods have different access modifiers? Yes. Access modifiers don't affect method signature. You can have a public and private overload.
Q8: Can we overload methods in different classes (parent and child)? Yes. If a child class defines a method with the same name but different parameters than the parent, it's overloading (not overriding). The child effectively has both methods available.
Q9: What is the resolution priority when multiple overloads match? Priority order: (1) Exact match, (2) Widening primitive conversion, (3) Autoboxing/unboxing, (4) Varargs. Java picks the most specific method. If two methods are equally applicable, you get a compile-time ambiguity error.
Q10: Can we overload methods with generics? Type erasure can cause issues. void print(List<String> list) and void print(List<Integer> list) are the SAME after erasure (both become List), so this doesn't compile. You need different method names or different parameter counts.
Q11: What happens when null is passed to overloaded methods? Java picks the most specific type. For print(String s) vs print(Object o), calling print(null) invokes print(String) because String is more specific than Object. If two types are at the same level (e.g., String vs Integer), it's ambiguous.
Q12: Is operator overloading possible in Java? No. Java doesn't support operator overloading (unlike C++ or Kotlin). The only exception is + which is overloaded for String concatenation by the compiler itself. This is a deliberate design choice for simplicity and readability.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Method Overloading in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, oops, method, overloading
Related Java Master Course Topics