methods
parameters, return values, overloading and varargs.
- chapter
- chapter 02.09
- reading time
- 7 min read
a method is a named block of code with parameters (inputs) and a return type (the one value it hands back). every call gets a fresh frame with fresh copies of the arguments. several methods can share a name if their parameter lists differ (overloading), and varargs (int... xs) lets one take any number of arguments, delivered as an array.
the picture
a method is a recipe card. the name is the title, the parameters are the ingredient list ("2 eggs, 1 cup flour"), the body is the instructions, and the return value is the dish you hand back. every time someone cooks from the card, they start with their own fresh ingredients (a new frame) and the card itself never changes.
{}
the inputs, each with a type and a name. every call gets its own fresh copies in a new stack frame, filled with the arguments the caller passed. they're just local variables that start with a value.
public class Main {
static int max(int a, int b) {
int bigger = a > b ? a : b;
return bigger;
}
public static void main(String[] args) {
IO.println(max(3, 7) + " " + max(-2, -9));
}
}7 -2
what a call actually does
calling a method pushes a new frame onto the call stack, copies each argument into the matching parameter, runs the body, and when it hits return, pops the frame and hands the value back to the caller, right in the middle of whatever expression made the call.
- 1public class Main {
- 2 static int square(int x) {
- 3 return x * x;
- 4 }
- 5
- 6 static int sumOfSquares(int a, int b) {
- 7 int s = square(a) + square(b);
- 8 return s;
- 9 }
- 10
- 11 public static void main(String[] args) {
- 12 int r = sumOfSquares(3, 4);
- 13 System.out.println(r);
- 14 }
- 15}
·main is about to call sumOfSquares(3, 4).
square runs twice, and each call gets its own frame with its own x.two things worth noticing. parameters are copies: square changing its x could never touch a in the caller (that's pass-by-value, and it holds for objects too, in a way that surprises people). and locals are gone the instant the method returns, which is why a method can't hand you a reference to its local int, only the value.
overloading
two methods can have the same name as long as their parameter lists differ: println(int), println(String), println(double)... that's why one println can print anything. the compiler picks which one to call from the types of the arguments, at compile time.
when more than one could fit, java searches in three rounds and stops at the first round that finds a match:
- phase 1: exact types, widening (
int→long), subclasses. no boxing, no varargs. - phase 2: also allow boxing and unboxing (
int↔Integer). - phase 3: also allow varargs.
within a round, the most specific candidate wins (int beats long beats double, Integer beats Object).
static String m(long x) { ... }static String m(Integer x) { ... }static String m(int... x) { ... }m(5); // int
widening: int → long, no boxing needed, so it's found in phase 1. among the ones that fit, the most specific (narrowest) type wins.
static String m(long x) { return "long"; }
static String m(Integer x) { return "Integer"; }
IO.println(m(5));the return type plays no part in choosing, which is why you can't overload on it:
int f(int a) { return 1; }
long f(int a) { return 2; }error: method f(int) is already defined. same name, same parameter types, same signature, whatever they return.
varargs
put ... after the last parameter's type and the method accepts any number of arguments of that type, including zero. inside the method, it's simply an array:
void main() {
IO.println(sum() + " " + sum(5) + " " + sum(1, 2, 3) + " " + sum(new int[] {4, 5}));
}
int sum(int... nums) {
int total = 0;
for (int n : nums) total += n;
return total;
}0 5 6 9
sum(1, 2, 3): the compiler wrapped the three arguments in a new int[], and nums is a reference to it. sum() gets an empty array, never null.only the last parameter can be varargs, and there can be just one. String.format(String format, Object... args) and List.of(E... elements) are the varargs methods you'll meet most.
- a method: modifiers, return type, name, parameters, body.
voidreturns nothing. - every call gets a new frame with fresh copies of the arguments. locals die on return.
- the signature is name + parameter types. you can't overload on return type alone.
- overload resolution: exact or widening first, then boxing, then varargs. most specific wins.
- varargs
T...arrives as an array (empty when there are no arguments). last parameter only.