Topic 5 of 13 · Lectures 7–8
Overloading, Objects as Parameters & Recursion
Methods and constructors that share a name, how Java passes arguments (always by value — even references), returning objects, and solving problems with recursion.
← → move between slides · F full screen · M slide list
Before we start
Why this matters
Why can you call System.out.println(5), println("hi") and println(3.14) — is println one method or many?
It is many: PrintStream declares ten methods called println, each with a different parameter list. The compiler picks the best match. That is overloading.
This topic also answers a question that trips up most students: when you pass an object to a method, can the method change it? And it introduces methods that call themselves.
Outline · Lectures 7–8
Topics in this chapter
Select a topic to jump to the slide that explains it.
Concept 1 of 5
Method overloading
class Calc {
int add(int a, int b) { return a + b; }
int add(int a, int b, int c) { return a + b + c; }
double add(double a, double b) { return a + b; }
String add(String a, String b) { return a + b; }
}
Calc c = new Calc();
c.add(2, 3); // 5 → add(int, int)
c.add(2, 3, 4); // 9 → add(int, int, int)
c.add(2.5, 1); // 3.5 → add(double, double)
c.add("OO", "P"); // "OOP" → add(String, String)- Overloaded methods share a name but differ in the number, types or order of parameters.
- The return type alone is not enough:
int f()anddouble f()clash. - The compiler chooses: exact match → widening (int→long→double) → boxing (int→Integer) → varargs.
- If two choices are equally good, the call is ambiguous and does not compile.
Interactive
Which overload runs?
Concept 2 of 5
Constructor overloading and this(...)
class Box {
double w, h, d;
Box() { // unit cube
this(1, 1, 1);
}
Box(double side) { // cube
this(side, side, side);
}
Box(double w, double h, double d) {
this.w = w; this.h = h; this.d = d;
}
}- Several constructors give callers several ways to create an object.
this(...)calls another constructor of the same class, so the real work is written once.this(...)must be the first statement in the constructor.
Step through the code
Trace: constructor chaining with this(...)
Watch the call stack grow as one constructor hands over to another.
Step through the code
Trace: constructor chaining with this(...) (cont.)
Concept 3 of 5
Passing arguments: always by value
- Java copies the value of each argument into the parameter.
- For a primitive, the value is the number itself: changing the parameter never affects the caller.
- For an object, the value is a reference: the method can change the object’s fields through it…
- …but assigning a new object to the parameter only changes the method’s copy of the arrow.
Step through the code
Trace: what can a method change?
Three methods try to change the caller’s data. Before stepping, predict the final line: k and p.x.
Step through the code
Trace: what can a method change? (cont.)
Code example
Returning objects
class Fraction { private final int num, den; Fraction(int n, int d) { int g = gcd(Math.abs(n), Math.abs(d)); num = n / g; den = d / g; } Fraction add(Fraction o) { // returns a NEW object return new Fraction(num * o.den + o.num * den, den * o.den); } boolean equals(Fraction o) { return num == o.num && den == o.den; } static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } public String toString() { return num + "/" + den; } } Fraction a = new Fraction(1, 2), b = new Fraction(1, 3); Fraction c = a.add(b); System.out.println(a + " + " + b + " = " + c); System.out.println(a.add(a).equals(new Fraction(1, 1)));1/2 + 1/3 = 5/6 true
- A method can create an object and return its reference; the object outlives the method call.
- Methods that return objects can be chained:
a.add(b).add(c). - Passing another object of the same class (
o) lets a method read its private fields, because access is checked per class.
Concept 4 of 5
Recursion
Recursion
static int fact(int n) {
if (n <= 1) return 1; // base case
return n * fact(n - 1); // recursive case
}
static int fib(int n) {
if (n < 2) return n;
return fib(n - 1) + fib(n - 2);
}- A recursive method calls itself on a smaller problem.
- Every recursion needs a base case that stops it; without one you get
StackOverflowError. - Each call gets its own stack frame with its own
n.
Step through the code
Trace: factorial on the call stack
The stack grows with every call until the base case, then the results multiply back up as the frames return.
Step through the code
Trace: factorial on the call stack (cont.)
Code example
More recursive methods
static int sumDigits(int n) { return n < 10 ? n : n % 10 + sumDigits(n / 10); } static long power(long b, int e) { // fast: halves e if (e == 0) return 1; long half = power(b, e / 2); return e % 2 == 0 ? half * half : half * half * b; } static String reverse(String s) { if (s.length() <= 1) return s; return reverse(s.substring(1)) + s.charAt(0); } static void hanoi(int n, char from, char to, char via) { if (n == 0) return; hanoi(n - 1, from, via, to); System.out.println("disk " + n + ": " + from + " ->" + to); hanoi(n - 1, via, to, from); } System.out.println(sumDigits(4096) + "" + power(2, 10) + "" + reverse("java")); hanoi(2, 'A', 'C', 'B');19 1024 avaj disk 1: A -> B disk 2: A -> C disk 1: B -> C
Step through the code
Trace: Tower of Hanoi on the call stack
Each call gets its own frame with its own n, from, to and via. Watch the stack grow to the base case and shrink again.
Step through the code
Trace: Tower of Hanoi on the call stack (cont.)
Concept 5 of 5
Recursion or iteration?
| Recursion | Iteration (loop) | |
|---|---|---|
| Code | Short and close to the maths definition | Often longer, uses explicit variables |
| Memory | One stack frame per call (deep recursion → StackOverflowError) | Constant extra memory |
| Speed | Call overhead; naive fib repeats work (exponential!) | Usually faster |
| Natural for | Trees, divide and conquer, backtracking, Tower of Hanoi | Counting, scanning arrays |
Worked example 1 of 3
Worked example 1
print(5) if the class has only print(long x) and print(Integer x)?Show the solution
print(long). Widening (int → long) is preferred over boxing (int → Integer).Worked example 2 of 3
Worked example 2
static void swap(int a, int b) { int t = a; a = b; b = t; }int x = 1, y = 2; swap(x, y); System.out.println(x + " " + y);Show the solution
Worked example 3 of 3
Worked example 3
Show the solution
static int count(String s, char c) {
if (s.isEmpty()) return 0;
return (s.charAt(0) == c ? 1 : 0) + count(s.substring(1), c);
}
// count("banana", 'a') → 3Practice
Practice (1 of 2)
Try each one on paper first, then check your answer.
void f(int a, double b) and void f(double a, int b) valid overloads? Is f(1, 2) OK?Show the answer
f(1, 2) is ambiguous — each needs one widening — so it does not compile.Time: Time() = 00:00, Time(h), Time(h, m), using this(...).Show the answer
Time() { this(0, 0); }
Time(int h) { this(h, 0); }
Time(int h, int m) { this.h = h; this.m = m; }arr[0] = 99; on an array parameter. Does the caller see it?Show the answer
Practice
Practice (2 of 2)
Try each one on paper first, then check your answer.
gcd(a, b).Show the answer
static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }fib(5) make in total?Show the answer
Point midpoint(Point p) that returns a new Point halfway between this and p.Show the answer
Point midpoint(Point p) {
return new Point((x + p.x) / 2, (y + p.y) / 2);
}Check yourself
Quiz
Summary
Summary
- Overloading = same name, different parameter lists; the compiler picks at compile time (exact → widening → boxing → varargs).
- Overloaded constructors can delegate with this(...) as the first statement.
- Java is always pass-by-value: primitives are copied; for objects the reference is copied, so fields can change but reassignment cannot escape.
- Methods can create and return objects, enabling chaining like a.add(b).add(c).
- Recursion needs a base case and a smaller subproblem; each call has its own stack frame.