Home
5Overloading, Objects as Parameters & Recursion
5

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.

  1. Method overloading
  2. Constructor overloading
  3. Passing objects as parameters
  4. Returning objects
  5. Recursion

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() and double 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

The method receives a copy of the reference, so both arrows point at the same object.
  • 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)));
Output
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

fib(4) calls fib(3) and fib(2) … the same values are computed many times.

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');
Output
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?

RecursionIteration (loop)
CodeShort and close to the maths definitionOften longer, uses explicit variables
MemoryOne stack frame per call (deep recursion → StackOverflowError)Constant extra memory
SpeedCall overhead; naive fib repeats work (exponential!)Usually faster
Natural forTrees, divide and conquer, backtracking, Tower of HanoiCounting, scanning arrays
Rule of thumb: Any recursion can be rewritten as a loop (possibly with an explicit stack). Choose whichever is clearer; switch to a loop when the depth could be huge.

Worked example 1 of 3

Worked example 1

Which method is called by 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

What does this print?
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
1 2. swap received copies of the values; the caller’s variables never change. (Java cannot write a swap for two int variables.)

Worked example 3 of 3

Worked example 3

Write a recursive method that counts how many times a character occurs in a String.
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') → 3

Practice

Practice (1 of 2)

Try each one on paper first, then check your answer.

1. Are void f(int a, double b) and void f(double a, int b) valid overloads? Is f(1, 2) OK?
Show the answer
Yes, they are valid overloads (different order). But f(1, 2) is ambiguous — each needs one widening — so it does not compile.
2. Write constructors for 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; }
3. A method does arr[0] = 99; on an array parameter. Does the caller see it?
Show the answer
Yes. The parameter refers to the same array object.

Practice

Practice (2 of 2)

Try each one on paper first, then check your answer.

4. Write a recursive gcd(a, b).
Show the answer
static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); }
5. How many calls does naive fib(5) make in total?
Show the answer
15 calls (fib(5) → fib(4), fib(3) … count every node of the call tree).
6. Write a method 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.