Method Overloading Rules
Understand how Java resolves overloaded methods and common ambiguity pitfalls.
Method Overloading Rules is a free Java Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Method Overloading Rules
Method overloading lets you define multiple methods with the same name but different parameter lists. Java selects the best match at compile time using precise resolution rules.
What is Overloading?
Overloaded methods share a name but differ in parameter count, type, or order. The return type alone is NOT sufficient to overload.
class Calculator {
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
// compile error — same signature, different return type only:
// long add(int a, int b) { return a + b; }
}
Calculator calc = new Calculator();
System.out.println(calc.add(1, 2)); // 3 (int)
System.out.println(calc.add(1.5, 2.5)); // 4.0 (double)
System.out.println(calc.add(1, 2, 3)); // 6 (3-arg)Resolution: Most Specific Match
Java picks the most specific applicable method. Widening, autoboxing, and varargs are tried in order of preference.
static void print(int x) { System.out.println("int: " + x); }
static void print(long x) { System.out.println("long: " + x); }
static void print(Object x) { System.out.println("Object: " + x); }
print(42); // int: 42 (exact match — most specific)
print(42L); // long: 42 (exact match)
print(3.14); // Object: 3.14 (no float match, widening then autoboxing)Widening Before Autoboxing
Java prefers widening a primitive over autoboxing it to a wrapper. This can produce surprising results.
static void display(long n) { System.out.println("long: " + n); }
static void display(Integer n) { System.out.println("Integer: " + n); }
int x = 100;
display(x); // long: 100 — widens int to long BEFORE autoboxing to Integer
// This surprises many developers!
static void show(Long n) { System.out.println("Long"); }
static void show(Integer n) { System.out.println("Integer"); }
// show(100); // compile error — ambiguous! Neither is more specificNull Argument Ambiguity
Passing null to overloaded methods can be ambiguous if multiple methods accept reference types. Cast null to resolve.
static void handle(String s) { System.out.println("String: " + s); }
static void handle(Integer i) { System.out.println("Integer: " + i); }
static void handle(Object o) { System.out.println("Object"); }
handle((String) null); // String: null (cast resolves ambiguity)
handle((Integer) null); // Integer: null
// handle(null); // compile error: ambiguous (String vs Integer)Overloading with Inheritance
Method resolution considers the declared type of the reference variable, not the runtime type — this is a compile-time decision.
class Animal {}
class Dog extends Animal {}
static void greet(Animal a) { System.out.println("Animal"); }
static void greet(Dog d) { System.out.println("Dog"); }
Animal a = new Dog(); // declared as Animal
greet(a); // Animal — compile-time type is Animal!
Dog d = new Dog();
greet(d); // Dog — compile-time type is DogOverloading vs Overriding
Overloading is a compile-time decision (static dispatch). Overriding is a runtime decision (dynamic dispatch) based on the actual object type.
class Base {
void run() { System.out.println("Base.run"); }
}
class Sub extends Base {
@Override
void run() { System.out.println("Sub.run"); } // overriding
void run(int speed) { System.out.println("Sub.run(" + speed + ")"); } // overloading
}
Base b = new Sub();
b.run(); // Sub.run — override (runtime dispatch)
// b.run(10); // compile error — Base doesn't have run(int)Common Overloading Patterns
Common uses of overloading in APIs: providing convenience methods that delegate to a full-parameter version.
class Connection {
void connect(String host, int port, int timeout) {
System.out.println("Connecting to " + host + ":" + port + " timeout=" + timeout);
}
// Convenience overloads
void connect(String host, int port) {
connect(host, port, 30); // delegate with default timeout
}
void connect(String host) {
connect(host, 5432); // delegate with default port
}
}
new Connection().connect("db.example.com");
// Connecting to db.example.com:5432 timeout=30Overloading and Generics
Generic method overloading requires care — type erasure can make two seemingly different signatures identical after compilation.
// Type erasure problem: both methods erase to the same signature!
// static void process(List<String> list) {} // compile error
// static void process(List<Integer> list) {} // duplicate after erasure
// Solutions:
// 1. Use different method names: processStrings / processIntegers
// 2. Use a generic method with bounded type:
static <T extends Number> void processNumbers(List<T> list) {
list.forEach(n -> System.out.println(n.doubleValue()));
}
processNumbers(List.of(1, 2, 3));
processNumbers(List.of(1.5, 2.5));Practical: Builder-Style Overloads
Overloading is common in builder/factory APIs to provide flexible object creation.
class Notification {
final String title, body;
final String imageUrl;
final boolean urgent;
// Factory overloads for convenience
static Notification simple(String title, String body) {
return new Notification(title, body, null, false);
}
static Notification urgent(String title, String body) {
return new Notification(title, body, null, true);
}
static Notification withImage(String title, String body, String url) {
return new Notification(title, body, url, false);
}
Notification(String title, String body, String imageUrl, boolean urgent) {
this.title = title; this.body = body;
this.imageUrl = imageUrl; this.urgent = urgent;
}
}Overloading Pitfalls
Avoid these common overloading mistakes:
- Too many overloads for the same operation — use a builder instead
- Overloads that differ only in parameter order — confusing
- Surprising widening: an int may resolve to long instead of Integer
// Confusing: order-based overloads
// void save(String name, int age) {}
// void save(int age, String name) {} // very confusing!
// Better: use a record/DTO
record UserData(String name, int age) {}
void save(UserData data) {}
// Surprising widening
static void m(long x) { System.out.println("long"); }
static void m(Integer x){ System.out.println("Integer"); }
int v = 5;
m(v); // long! widening preferred over autoboxingQuick Check
If a method is overloaded with both long and Integer parameters, which is chosen when passing an int argument?
Recap: Method Overloading Rules
Key takeaways:
- Overloading differs by parameter count, type, or order — NOT return type alone
- Java resolves overloads at compile time using the declared type of arguments
- Widening a primitive is preferred over autoboxing it to a wrapper
- Null arguments may cause ambiguity — cast to resolve: handle((String) null)
- Overloading is compile-time; overriding is runtime — they are different mechanisms
- Use convenience overloads that delegate to a full-parameter master method
Frequently asked questions
Is the “Method Overloading Rules” lesson free?
Yes — the full text of “Method Overloading Rules” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.
What will I learn in “Method Overloading Rules”?
Understand how Java resolves overloaded methods and common ambiguity pitfalls. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Java Academy?
No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Method Overloading Rules” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Java Academy lesson?
Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Method Overloading Rules
- Varargs Parameters
- Static Fields and Constants
- Utility Classes and Static Factory Methods